Browse Source

ref(replays): Compatibility layer between v0 events and v1 replay api (#37189)

The idea in this diff is to create `ReplayReader.getReplay()` and then (either in this PR's or followups) adjust all the downstream components to use it.

Also, updated the time variables to be clear about their unit: `durationMs` and `startTimestampMs`.
Ryan Albrecht 2 years ago
parent
commit
a9b2431659

+ 2 - 2
static/app/components/performance/waterfall/utils.tsx

@@ -156,8 +156,8 @@ export const getDurationDisplay = ({
 
 export const getHumanDuration = (duration: number): string => {
   // note: duration is assumed to be in seconds
-  const durationMS = duration * 1000;
-  return `${durationMS.toLocaleString(undefined, {
+  const durationMs = duration * 1000;
+  return `${durationMs.toLocaleString(undefined, {
     minimumFractionDigits: 2,
     maximumFractionDigits: 2,
   })}ms`;

+ 5 - 5
static/app/components/replays/breadcrumbs/gridlines.tsx

@@ -35,13 +35,13 @@ function Gridlines({
 }
 
 type Props = {
-  durationMS: number;
+  durationMs: number;
   width: number;
   minWidth?: number;
 };
 
-export function MajorGridlines({durationMS, minWidth = 50, width}: Props) {
-  const {timespan, cols, remaining} = countColumns(durationMS, width, minWidth);
+export function MajorGridlines({durationMs, minWidth = 50, width}: Props) {
+  const {timespan, cols, remaining} = countColumns(durationMs, width, minWidth);
 
   return (
     <Gridlines cols={cols} lineStyle="solid" remaining={remaining}>
@@ -50,8 +50,8 @@ export function MajorGridlines({durationMS, minWidth = 50, width}: Props) {
   );
 }
 
-export function MinorGridlines({durationMS, minWidth = 20, width}: Props) {
-  const {cols, remaining} = countColumns(durationMS, width, minWidth);
+export function MinorGridlines({durationMs, minWidth = 20, width}: Props) {
+  const {cols, remaining} = countColumns(durationMs, width, minWidth);
 
   return <Gridlines cols={cols} lineStyle="dotted" remaining={remaining} />;
 }

+ 8 - 8
static/app/components/replays/breadcrumbs/replayTimeline.tsx

@@ -31,8 +31,8 @@ function ReplayTimeline({}: Props) {
     return <Placeholder height="48px" bottomGutter={2} />;
   }
 
-  const durationMS = replay.getDurationMS();
-  const {startTimestamp} = replay.getEvent();
+  const durationMs = replay.getDurationMs();
+  const startTimestampMs = replay.getReplay().started_at.getTime();
   const crumbs = replay.getRawCrumbs() || [];
   const spans = replay.getRawSpans() || [];
   const userCrumbs = crumbs.filter(crumb => USER_ACTIONS.includes(crumb.type));
@@ -45,21 +45,21 @@ function ReplayTimeline({}: Props) {
         <Resizeable>
           {({width}) => (
             <Stacked>
-              <MinorGridlines durationMS={durationMS} width={width} />
-              <MajorGridlines durationMS={durationMS} width={width} />
+              <MinorGridlines durationMs={durationMs} width={width} />
+              <MajorGridlines durationMs={durationMs} width={width} />
               <TimelineScrubber />
               <UnderTimestamp paddingTop="36px">
                 <ReplayTimelineSpans
-                  durationMS={durationMS}
+                  durationMs={durationMs}
                   spans={networkSpans}
-                  startTimestamp={startTimestamp}
+                  startTimestampMs={startTimestampMs}
                 />
               </UnderTimestamp>
               <UnderTimestamp paddingTop="0">
                 <ReplayTimelineEvents
                   crumbs={userCrumbs}
-                  durationMS={durationMS}
-                  startTimestamp={startTimestamp}
+                  durationMs={durationMs}
+                  startTimestampMs={startTimestampMs}
                   width={width}
                 />
               </UnderTimestamp>

+ 16 - 11
static/app/components/replays/breadcrumbs/replayTimelineEvents.tsx

@@ -16,8 +16,8 @@ const EVENT_STICK_MARKER_WIDTH = 4;
 
 type Props = {
   crumbs: Crumb[];
-  durationMS: number;
-  startTimestamp: number;
+  durationMs: number;
+  startTimestampMs: number;
   width: number;
   className?: string;
 };
@@ -25,18 +25,23 @@ type Props = {
 function ReplayTimelineEvents({
   className,
   crumbs,
-  durationMS,
-  startTimestamp,
+  durationMs,
+  startTimestampMs,
   width,
 }: Props) {
   const totalColumns = Math.floor(width / EVENT_STICK_MARKER_WIDTH);
-  const eventsByCol = getCrumbsByColumn(startTimestamp, durationMS, crumbs, totalColumns);
+  const eventsByCol = getCrumbsByColumn(
+    startTimestampMs,
+    durationMs,
+    crumbs,
+    totalColumns
+  );
 
   return (
     <Timeline.Columns className={className} totalColumns={totalColumns} remainder={0}>
       {Array.from(eventsByCol.entries()).map(([column, breadcrumbs]) => (
         <EventColumn key={column} column={column}>
-          <Event crumbs={breadcrumbs} startTimestamp={startTimestamp} />
+          <Event crumbs={breadcrumbs} startTimestampMs={startTimestampMs} />
         </EventColumn>
       ))}
     </Timeline.Columns>
@@ -55,10 +60,10 @@ const EventColumn = styled(Timeline.Col)<{column: number}>`
 
 function Event({
   crumbs,
-  startTimestamp,
+  startTimestampMs,
 }: {
   crumbs: Crumb[];
-  startTimestamp: number;
+  startTimestampMs: number;
   className?: string;
 }) {
   const {setCurrentTime} = useReplayContext();
@@ -66,17 +71,17 @@ function Event({
   const handleClick = useCallback(
     (crumb: Crumb) => {
       crumb.timestamp !== undefined
-        ? setCurrentTime(relativeTimeInMs(crumb.timestamp, startTimestamp))
+        ? setCurrentTime(relativeTimeInMs(crumb.timestamp, startTimestampMs))
         : null;
     },
-    [setCurrentTime, startTimestamp]
+    [setCurrentTime, startTimestampMs]
   );
 
   const title = crumbs.map(crumb => (
     <BreadcrumbItem
       key={crumb.id}
       crumb={crumb}
-      startTimestamp={startTimestamp}
+      startTimestampMs={startTimestampMs}
       isHovered={false}
       isSelected={false}
       onClick={handleClick}

+ 6 - 7
static/app/components/replays/breadcrumbs/replayTimelineSpans.tsx

@@ -11,7 +11,7 @@ type Props = {
   /**
    * Duration, in milliseconds, of the timeline
    */
-  durationMS: number;
+  durationMs: number;
 
   /**
    * The spans to render into the timeline
@@ -21,7 +21,7 @@ type Props = {
   /**
    * Timestamp when the timeline begins, in milliseconds
    */
-  startTimestamp: number;
+  startTimestampMs: number;
 
   /**
    * Extra classNames
@@ -29,16 +29,15 @@ type Props = {
   className?: string;
 };
 
-function ReplayTimelineEvents({className, durationMS, spans, startTimestamp}: Props) {
+function ReplayTimelineEvents({className, durationMs, spans, startTimestampMs}: Props) {
   const flattenedSpans = flattenSpans(spans);
 
-  const startMs = startTimestamp * 1000;
   return (
     <Spans className={className}>
       {flattenedSpans.map((span, i) => {
-        const sinceStart = span.startTimestamp - startMs;
-        const startPct = divide(sinceStart, durationMS);
-        const widthPct = divide(span.duration, durationMS);
+        const sinceStart = span.startTimestamp - startTimestampMs;
+        const startPct = divide(sinceStart, durationMs);
+        const widthPct = divide(span.duration, durationMs);
 
         const requestsCount = tn(
           '%s network request',

+ 7 - 8
static/app/components/replays/header/detailsPageBreadcrumbs.tsx

@@ -5,20 +5,19 @@ import Breadcrumbs from 'sentry/components/breadcrumbs';
 import FeatureBadge from 'sentry/components/featureBadge';
 import Placeholder from 'sentry/components/placeholder';
 import {t} from 'sentry/locale';
-import {Event} from 'sentry/types/event';
+import type {ReplayRecord} from 'sentry/views/replays/types';
 
 type Props = {
   orgId: string;
-  event?: Event;
+  replayRecord: ReplayRecord | undefined;
 };
 
-function DetailsPageBreadcrumbs({orgId, event}: Props) {
+function DetailsPageBreadcrumbs({orgId, replayRecord}: Props) {
   const labelTitle =
-    event?.user?.name ||
-    event?.user?.email ||
-    event?.user?.username ||
-    event?.user?.ip_address ||
-    event?.user?.id;
+    replayRecord?.user.name ||
+    replayRecord?.user.email ||
+    replayRecord?.user.ip ||
+    replayRecord?.user.id;
 
   return (
     <Breadcrumbs

+ 4 - 4
static/app/components/replays/player/scrubber.tsx

@@ -13,10 +13,10 @@ type Props = {
 
 function Scrubber({className}: Props) {
   const {currentHoverTime, currentTime, replay, setCurrentTime} = useReplayContext();
-  const durationMS = replay?.getDurationMS();
+  const durationMs = replay?.getDurationMs();
 
-  const percentComplete = divide(currentTime, durationMS);
-  const hoverPlace = divide(currentHoverTime || 0, durationMS);
+  const percentComplete = divide(currentTime, durationMs);
+  const hoverPlace = divide(currentHoverTime || 0, durationMs);
 
   return (
     <Wrapper className={className}>
@@ -28,7 +28,7 @@ function Scrubber({className}: Props) {
         <Range
           name="replay-timeline"
           min={0}
-          max={durationMS}
+          max={durationMs}
           value={Math.round(currentTime)}
           onChange={value => setCurrentTime(value || 0)}
           showLabel={false}

+ 4 - 4
static/app/components/replays/player/scrubberMouseTracking.tsx

@@ -9,11 +9,11 @@ type Props = {
 
 function ScrubberMouseTracking({children}: Props) {
   const {replay, setCurrentHoverTime} = useReplayContext();
-  const durationMS = replay?.getDurationMS();
+  const durationMs = replay?.getDurationMs();
 
   const handlePositionChange = useCallback(
     params => {
-      if (!params || durationMS === undefined) {
+      if (!params || durationMs === undefined) {
         setCurrentHoverTime(undefined);
         return;
       }
@@ -21,13 +21,13 @@ function ScrubberMouseTracking({children}: Props) {
 
       if (left >= 0) {
         const percent = left / width;
-        const time = percent * durationMS;
+        const time = percent * durationMs;
         setCurrentHoverTime(time);
       } else {
         setCurrentHoverTime(undefined);
       }
     },
-    [durationMS, setCurrentHoverTime]
+    [durationMs, setCurrentHoverTime]
   );
 
   const mouseTrackingProps = useMouseTracking<HTMLDivElement>({

+ 4 - 4
static/app/components/replays/playerRelativeTime.tsx

@@ -5,12 +5,12 @@ import {showPlayerTime} from 'sentry/components/replays/utils';
 import Tooltip from 'sentry/components/tooltip';
 
 type Props = {
-  relativeTime: number | undefined;
+  relativeTimeMs: number | undefined;
   timestamp: string | undefined;
 };
 
-const PlayerRelativeTime = ({relativeTime, timestamp}: Props) => {
-  if (!timestamp || !relativeTime) {
+const PlayerRelativeTime = ({relativeTimeMs, timestamp}: Props) => {
+  if (!timestamp || !relativeTimeMs) {
     return <div />;
   }
 
@@ -23,7 +23,7 @@ const PlayerRelativeTime = ({relativeTime, timestamp}: Props) => {
       underlineColor="gray300"
       showUnderline
     >
-      <Value>{showPlayerTime(timestamp, relativeTime)}</Value>
+      <Value>{showPlayerTime(timestamp, relativeTimeMs)}</Value>
     </Tooltip>
   );
 };

+ 7 - 7
static/app/components/replays/replayController.tsx

@@ -85,8 +85,8 @@ function ReplayPlayPauseBar({isCompact}: {isCompact: boolean}) {
           title={t('Next breadcrumb')}
           icon={<IconNext size="sm" />}
           onClick={() => {
-            const startTimestampSec = replay?.getEvent().startTimestamp;
-            if (!startTimestampSec) {
+            const startTimestampMs = replay?.getReplay().started_at?.getTime();
+            if (!startTimestampMs) {
               return;
             }
             const transformedCrumbs = transformCrumbs(replay?.getRawCrumbs() || []);
@@ -94,11 +94,11 @@ function ReplayPlayPauseBar({isCompact}: {isCompact: boolean}) {
               crumbs: transformedCrumbs.filter(crumb =>
                 USER_ACTIONS.includes(crumb.type)
               ),
-              targetTimestampMs: startTimestampSec * 1000 + currentTime,
+              targetTimestampMs: startTimestampMs + currentTime,
             });
 
-            if (startTimestampSec !== undefined && next?.timestamp) {
-              setCurrentTime(relativeTimeInMs(next.timestamp, startTimestampSec));
+            if (startTimestampMs !== undefined && next?.timestamp) {
+              setCurrentTime(relativeTimeInMs(next.timestamp, startTimestampMs));
             }
           }}
           aria-label={t('Fast-forward to next breadcrumb')}
@@ -110,11 +110,11 @@ function ReplayPlayPauseBar({isCompact}: {isCompact: boolean}) {
 
 function ReplayCurrentTime() {
   const {currentTime, replay} = useReplayContext();
-  const durationMS = replay?.getDurationMS();
+  const durationMs = replay?.getDurationMs();
 
   return (
     <span>
-      {formatTime(currentTime)} / {durationMS ? formatTime(durationMS) : '??:??'}
+      {formatTime(currentTime)} / {durationMs ? formatTime(durationMs) : '??:??'}
     </span>
   );
 }

Some files were not shown because too many files changed in this diff