From 74e7210da5a560b8054c6c4cb13bc774f7390ca8 Mon Sep 17 00:00:00 2001 From: Michelle Zhang <56095982+michellewzhang@users.noreply.github.com> Date: Fri, 3 May 2024 16:09:45 -0700 Subject: [PATCH] feat(replay): show screen name in url bar for mobile replays --- .../eventReplay/replayPreviewPlayer.tsx | 6 ++- .../replays/replayCurrentScreen.tsx | 38 +++++++++++++++++++ static/app/components/replays/replayView.tsx | 3 +- .../utils/replays/getCurrentScreenName.tsx | 20 ++++++++++ static/app/utils/replays/replayReader.tsx | 8 ++++ 5 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 static/app/components/replays/replayCurrentScreen.tsx create mode 100644 static/app/utils/replays/getCurrentScreenName.tsx diff --git a/static/app/components/events/eventReplay/replayPreviewPlayer.tsx b/static/app/components/events/eventReplay/replayPreviewPlayer.tsx index 35508b6c5a0e78..b9099cefef87bf 100644 --- a/static/app/components/events/eventReplay/replayPreviewPlayer.tsx +++ b/static/app/components/events/eventReplay/replayPreviewPlayer.tsx @@ -6,6 +6,7 @@ import {Button, LinkButton} from 'sentry/components/button'; import ErrorBoundary from 'sentry/components/errorBoundary'; import Panel from 'sentry/components/panels/panel'; import {useReplayContext} from 'sentry/components/replays/replayContext'; +import ReplayCurrentScreen from 'sentry/components/replays/replayCurrentScreen'; import ReplayCurrentUrl from 'sentry/components/replays/replayCurrentUrl'; import {ReplayFullscreenButton} from 'sentry/components/replays/replayFullscreenButton'; import ReplayPlayer from 'sentry/components/replays/replayPlayer'; @@ -54,7 +55,8 @@ function ReplayPreviewPlayer({ const location = useLocation(); const organization = useOrganization(); const [isSidebarOpen, setIsSidebarOpen] = useState(true); - const {replay, currentTime, isFetching, isFinished, isPlaying} = useReplayContext(); + const {replay, currentTime, isFetching, isFinished, isPlaying, isVideoReplay} = + useReplayContext(); const eventView = EventView.fromLocation(location); const fullscreenRef = useRef(null); @@ -103,7 +105,7 @@ function ReplayPreviewPlayer({ {isFullscreen ? ( - + {isVideoReplay ? : } { + try { + return getCurrentScreenName(frames, currentTime); + } catch (err) { + Sentry.captureException(err); + return ''; + } + }, [frames, currentTime]); + + if (!replay || !screenName) { + return ( + + {''} + + ); + } + + return ( + + {screenName} + + ); +} + +export default ReplayCurrentScreen; diff --git a/static/app/components/replays/replayView.tsx b/static/app/components/replays/replayView.tsx index ebbad961cca858..bf8e5972ebeea2 100644 --- a/static/app/components/replays/replayView.tsx +++ b/static/app/components/replays/replayView.tsx @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; import {useReplayContext} from 'sentry/components/replays/replayContext'; import ReplayController from 'sentry/components/replays/replayController'; +import ReplayCurrentScreen from 'sentry/components/replays/replayCurrentScreen'; import ReplayCurrentUrl from 'sentry/components/replays/replayCurrentUrl'; import ReplayPlayer from 'sentry/components/replays/replayPlayer'; import ReplayProcessingError from 'sentry/components/replays/replayProcessingError'; @@ -30,7 +31,7 @@ function ReplayView({toggleFullscreen}: Props) { - + {isVideoReplay ? : } {isFullscreen ? ( frame.offsetMs < currentOffsetMS + ); + + const mostRecentFrame = framesBeforeCurrentOffset?.at(-1) ?? frames?.at(0); + if (!mostRecentFrame) { + return ''; + } + + return mostRecentFrame.data.to; +} + +export default getCurrentScreenName; diff --git a/static/app/utils/replays/replayReader.tsx b/static/app/utils/replays/replayReader.tsx index 76ccb221b2c909..8574ed860dbfb2 100644 --- a/static/app/utils/replays/replayReader.tsx +++ b/static/app/utils/replays/replayReader.tsx @@ -429,6 +429,14 @@ export default class ReplayReader { ].sort(sortFrames) ); + getMobileNavigationFrames = memoize(() => + [ + ...this._sortedBreadcrumbFrames.filter(frame => + ['replay.init', 'navigation'].includes(frame.category) + ), + ].sort(sortFrames) + ); + getNetworkFrames = memoize(() => this._sortedSpanFrames.filter( frame => frame.op.startsWith('navigation.') || frame.op.startsWith('resource.')