From 6c83718264e9a0459104db92bc530d548ffa4695 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:04:04 -0700 Subject: [PATCH 01/26] Initial start, stop, and link w/project platform --- .../devtoolbar/components/navigation.tsx | 2 + .../devtoolbar/components/panelRouter.tsx | 3 + .../components/replay/replayPanel.tsx | 147 ++++++++++++++++++ .../devtoolbar/hooks/useToolbarRoute.tsx | 9 +- 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 static/app/components/devtoolbar/components/replay/replayPanel.tsx diff --git a/static/app/components/devtoolbar/components/navigation.tsx b/static/app/components/devtoolbar/components/navigation.tsx index 24607c54b3750f..0f6e1a7601d316 100644 --- a/static/app/components/devtoolbar/components/navigation.tsx +++ b/static/app/components/devtoolbar/components/navigation.tsx @@ -6,6 +6,7 @@ import { IconFlag, IconIssues, IconMegaphone, + IconPlay, IconReleases, IconSiren, } from 'sentry/icons'; @@ -58,6 +59,7 @@ export default function Navigation({ }> + } /> ); } diff --git a/static/app/components/devtoolbar/components/panelRouter.tsx b/static/app/components/devtoolbar/components/panelRouter.tsx index 9eea23f360e6ff..af2e389bcf1145 100644 --- a/static/app/components/devtoolbar/components/panelRouter.tsx +++ b/static/app/components/devtoolbar/components/panelRouter.tsx @@ -7,6 +7,7 @@ const PanelFeedback = lazy(() => import('./feedback/feedbackPanel')); const PanelIssues = lazy(() => import('./issues/issuesPanel')); const PanelFeatureFlags = lazy(() => import('./featureFlags/featureFlagsPanel')); const PanelReleases = lazy(() => import('./releases/releasesPanel')); +const PanelReplay = lazy(() => import('./replay/replayPanel')); export default function PanelRouter() { const {state} = useToolbarRoute(); @@ -22,6 +23,8 @@ export default function PanelRouter() { return ; case 'releases': return ; + case 'replay': + return ; default: return null; } diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx new file mode 100644 index 00000000000000..42ad0340938f39 --- /dev/null +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -0,0 +1,147 @@ +import {Fragment, useState} from 'react'; +import {css} from '@emotion/react'; + +import {Button} from 'sentry/components/button'; +import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink'; +import {listItemPlaceholderWrapperCss} from 'sentry/components/devtoolbar/styles/listItem'; +import { + resetFlexColumnCss, + resetFlexRowCss, +} from 'sentry/components/devtoolbar/styles/reset'; +import ProjectBadge from 'sentry/components/idBadge/projectBadge'; +import Placeholder from 'sentry/components/placeholder'; +import TextOverflow from 'sentry/components/textOverflow'; +import TimeSince from 'sentry/components/timeSince'; +import {IconPause, IconPlay} from 'sentry/icons'; +import {t} from 'sentry/locale'; +import type {PlatformKey} from 'sentry/types/project'; + +import useConfiguration from '../../hooks/useConfiguration'; +import {panelInsetContentCss, panelSectionCss} from '../../styles/panel'; +import {smallCss} from '../../styles/typography'; +import PanelLayout from '../panelLayout'; + +export function StartReplayButton({ + setReplayId, +}: { + setReplayId: React.Dispatch>; +}) { + const {SentrySDK} = useConfiguration(); + const replay = SentrySDK && 'getReplay' in SentrySDK && SentrySDK.getReplay(); + + const [isStarted, setIsStarted] = useState(false); + + return ( + + ); +} + +const TRUNC_ID_LENGTH = 10; // TODO: import this from somewhere else? Wrap/make dynamic? + +export default function ReleasesPanel() { + // const {data, isLoading, isError} = useToolbarRelease(); + const [isLoading, isError] = [false, false]; + + const {organizationSlug, projectSlug, projectId, projectPlatform, trackAnalytics} = + useConfiguration(); + + const estimateSize = 515; + const placeholderHeight = `${estimateSize - 8}px`; // The real height of the items, minus the padding-block value + + const [replayId, setReplayId] = useState(undefined); // b7908c02c0ea40f081077a84d887d1f6 + console.log(replayId); + + return ( + + {isLoading || isError ? ( +
+ +
+ ) : ( + + +
+ {replayId !== undefined ? ( + + {'Replay of current session: '} + { + trackAnalytics?.({ + eventKey: `devtoolbar.current-replay-link.click`, + eventName: `devtoolbar: Current replay link clicked`, + }); + }} + > +
+ + {/* TODO: can truncate if too 32 char is too long */} + {replayId.slice(0, TRUNC_ID_LENGTH)} +
+
+
+ ) : null} +
+ {/* TODO: add DURATION and start time, similar to replay index page */} + {/* {'1 min ago 01:12'} */} +
+ )} +
+ ); +} diff --git a/static/app/components/devtoolbar/hooks/useToolbarRoute.tsx b/static/app/components/devtoolbar/hooks/useToolbarRoute.tsx index 6ff627611fb668..5e0a65f8bf8550 100644 --- a/static/app/components/devtoolbar/hooks/useToolbarRoute.tsx +++ b/static/app/components/devtoolbar/hooks/useToolbarRoute.tsx @@ -1,7 +1,14 @@ import {createContext, useCallback, useContext, useState} from 'react'; type State = { - activePanel: null | 'alerts' | 'feedback' | 'issues' | 'featureFlags' | 'releases'; + activePanel: + | null + | 'alerts' + | 'feedback' + | 'issues' + | 'featureFlags' + | 'releases' + | 'replay'; }; const context = createContext<{ From 72868f613987a11806060fc833c6917af2bce887 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:17:17 -0700 Subject: [PATCH 02/26] more progress to MVP + improve comments --- package.json | 16 +- static/app/bootstrap/initializeSdk.tsx | 2 + .../components/replay/replayPanel.tsx | 68 +++--- yarn.lock | 195 +++++++++--------- 4 files changed, 156 insertions(+), 125 deletions(-) diff --git a/package.json b/package.json index dfb7b1535ebab8..8b46ff9921c839 100644 --- a/package.json +++ b/package.json @@ -59,13 +59,13 @@ "@sentry-internal/rrweb-player": "2.25.0", "@sentry-internal/rrweb-snapshot": "2.25.0", "@sentry/babel-plugin-component-annotate": "^2.16.1", - "@sentry/core": "^8.18.0", - "@sentry/node": "^8.18.0", - "@sentry/react": "^8.18.0", + "@sentry/core": "^8.20.0", + "@sentry/node": "^8.20.0", + "@sentry/react": "^8.20.0", "@sentry/release-parser": "^1.3.1", "@sentry/status-page-list": "^0.3.0", - "@sentry/types": "^8.18.0", - "@sentry/utils": "^8.18.0", + "@sentry/types": "^8.20.0", + "@sentry/utils": "^8.20.0", "@spotlightjs/spotlight": "^2.0.0-alpha.1", "@tanstack/react-query": "^4.29.7", "@tanstack/react-query-devtools": "^4.36.1", @@ -180,7 +180,7 @@ "@codecov/webpack-plugin": "^0.0.1-beta.8", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", "@sentry/jest-environment": "6.0.0", - "@sentry/profiling-node": "^8.18.0", + "@sentry/profiling-node": "^8.20.0", "@styled/typescript-styled-plugin": "^1.0.1", "@testing-library/dom": "10.1.0", "@testing-library/jest-dom": "6.4.5", @@ -263,9 +263,7 @@ "last 3 iOS major versions", "Firefox ESR" ], - "test": [ - "current node" - ] + "test": ["current node"] }, "volta": { "extends": ".volta.json" diff --git a/static/app/bootstrap/initializeSdk.tsx b/static/app/bootstrap/initializeSdk.tsx index a1c09c2dc1d49f..f5999191713d3c 100644 --- a/static/app/bootstrap/initializeSdk.tsx +++ b/static/app/bootstrap/initializeSdk.tsx @@ -175,6 +175,8 @@ export function initializeSdk(config: Config, {routes}: {routes?: Function} = {} return event; }, + + debug: true, }); if (process.env.NODE_ENV !== 'production') { diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 42ad0340938f39..711f3e27e31f67 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,5 +1,6 @@ import {Fragment, useState} from 'react'; import {css} from '@emotion/react'; +import type {replayIntegration} from '@sentry/react'; import {Button} from 'sentry/components/button'; import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink'; @@ -10,8 +11,6 @@ import { } from 'sentry/components/devtoolbar/styles/reset'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import Placeholder from 'sentry/components/placeholder'; -import TextOverflow from 'sentry/components/textOverflow'; -import TimeSince from 'sentry/components/timeSince'; import {IconPause, IconPlay} from 'sentry/icons'; import {t} from 'sentry/locale'; import type {PlatformKey} from 'sentry/types/project'; @@ -22,37 +21,48 @@ import {smallCss} from '../../styles/typography'; import PanelLayout from '../panelLayout'; export function StartReplayButton({ + replay, setReplayId, }: { + replay: ReturnType | undefined | false; setReplayId: React.Dispatch>; }) { - const {SentrySDK} = useConfiguration(); - const replay = SentrySDK && 'getReplay' in SentrySDK && SentrySDK.getReplay(); - const [isStarted, setIsStarted] = useState(false); + // isStarted is not always accurate, since we don't have an API fx to check if we're currently recording. + // _replay.recordingMode == "session" is how we'd check w/ the internal API. return ( + const [replayId, setReplayId] = useState(() => + replay?.getReplayId() ); -} + // Polls periodically since a replay could be started by sessionSampleRate + useEffect(() => { + const intervalId = setInterval( + () => setReplayId(replay?.getReplayId()), + POLL_INTERVAL_MS + ); + return () => clearInterval(intervalId); + }, [replay]); -const TRUNC_ID_LENGTH = 10; // TODO: import this from somewhere else? Make it more dynamic? - -export default function ReplayPanel() { - // TODO: re-estimate. This is from releasesPanel - const estimateSize = 515; - const placeholderHeight = `${estimateSize - 8}px`; // The real height of the items, minus the padding-block value + const [isRecording, setIsRecording] = useState( + () => replay?.getReplayId() !== undefined + ); + // Current replayId is only defined when there is an active recording session + useEffect(() => setIsRecording(replayId !== undefined), [replayId]); - const {projectSlug, projectId, projectPlatform, trackAnalytics, SentrySDK} = - useConfiguration(); - const replay = SentrySDK && 'getReplay' in SentrySDK && SentrySDK.getReplay(); - const [replayId, setReplayId] = useState(() => { - try { - if (replay) { - return replay.getReplayId(); - } - } catch { - return undefined; + // Used to persist the link to the last replay even if it's stopped. //TODO: this is lost after leaving the panel + const [lastReplayId, setLastReplayId] = useState(() => + replay?.getReplayId() + ); + useEffect(() => { + if (replayId) { + setLastReplayId(replayId); } - return undefined; - }); - console.log('Replay ID=', replayId); - - const [isLoading, isError] = [false, false]; // TODO: use if we query an endpoint for data like time started + }, [replayId]); return ( - {isLoading || isError ? ( -
+
- ) : ( - - -
- {replayId !== undefined ? ( - - {'Replay of current session: '} - { - trackAnalytics?.({ - eventKey: `devtoolbar.current-replay-link.click`, - eventName: `devtoolbar: Current replay link clicked`, - }); - }} + {isRecording + ? t('In progress. Click to stop recording') // TODO: make sure this fits + : t('Start recording the current session')} + +
+ {lastReplayId ? ( + + {isRecording ? t('Current replay: ') : t('Last recorded replay: ')} + { + trackAnalytics?.({ + eventKey: `devtoolbar.current-replay-link.click`, + eventName: `devtoolbar: Current replay link clicked`, + }); + }} + > +
-
- - {replayId.slice(0, TRUNC_ID_LENGTH)} -
- - - ) : ( - 'No replay' - )} -
- {/* TODO: add DURATION and start time, similar to replay index page */} - {/* {'1 min ago 01:12'} */} - - )} + + {lastReplayId.slice(0, TRUNC_ID_LENGTH)} +
+
+
+ ) : ( + 'No replay' + )} +
+
); } From c1e1ba75ecdba19b06c64b49009e3cdc12a84174 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 1 Aug 2024 16:00:02 -0700 Subject: [PATCH 04/26] Cleanup todos --- .../components/devtoolbar/components/replay/replayPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 3bed8e70570de4..4007b9e067eb51 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -65,14 +65,14 @@ export default function ReplayPanel() { } else { // If we're sampling errors, the we might be in buffering mode. // In this case start() will do nothing. flush() will switch to session mode + start recording. - replay.flush(); // TODO: make sure this works in session mode too + replay.flush(); } setReplayId(replay.getReplayId()); // this will set isRecording } }} > {isRecording - ? t('In progress. Click to stop recording') // TODO: make sure this fits + ? t('In progress. Click to stop recording') : t('Start recording the current session')}
From 1991afef9bf1f99ee1cb7b25a3f9222e2c8b8ae8 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:11:12 -0700 Subject: [PATCH 05/26] Handle buffer mode --- .../components/replay/replayPanel.tsx | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 4007b9e067eb51..30991977a92a1c 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,5 +1,6 @@ import {Fragment, useEffect, useState} from 'react'; import {css} from '@emotion/react'; +import type {ReplayRecordingMode} from '@sentry/types'; import {Button} from 'sentry/components/button'; import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink'; @@ -23,33 +24,40 @@ export default function ReplayPanel() { const replay = SentrySDK && 'getReplay' in SentrySDK ? SentrySDK.getReplay() : undefined; - const [replayId, setReplayId] = useState(() => + // sessionId is undefined iff we are recording in session OR buffer mode. + const [sessionId, setSessionId] = useState(() => replay?.getReplayId() ); + const [recordingMode, setRecordingMode] = useState( + () => replay?._replay.recordingMode + ); // Polls periodically since a replay could be started by sessionSampleRate useEffect(() => { - const intervalId = setInterval( - () => setReplayId(replay?.getReplayId()), - POLL_INTERVAL_MS - ); + const intervalId = setInterval(() => { + setSessionId(replay?.getReplayId()); + setRecordingMode(replay?._replay.recordingMode); + }, POLL_INTERVAL_MS); return () => clearInterval(intervalId); }, [replay]); const [isRecording, setIsRecording] = useState( - () => replay?.getReplayId() !== undefined + () => replay?.getReplayId() && replay?._replay.recordingMode === 'session' ); - // Current replayId is only defined when there is an active recording session - useEffect(() => setIsRecording(replayId !== undefined), [replayId]); - - // Used to persist the link to the last replay even if it's stopped. //TODO: this is lost after leaving the panel - const [lastReplayId, setLastReplayId] = useState(() => - replay?.getReplayId() + useEffect( + () => setIsRecording(sessionId && recordingMode === 'session'), + [sessionId, recordingMode] ); + + // Used to persist the link to the last recorded replay, even if it's stopped. + // TODO: this is lost after leaving the panel. Could use a local storage? + const [lastReplayId, setLastReplayId] = useState(() => { + return recordingMode === 'session' ? replay?.getReplayId() : undefined; + }); useEffect(() => { - if (replayId) { - setLastReplayId(replayId); + if (sessionId && recordingMode === 'session') { + setLastReplayId(sessionId); } - }, [replayId]); + }, [sessionId, recordingMode]); return ( @@ -67,7 +75,7 @@ export default function ReplayPanel() { // In this case start() will do nothing. flush() will switch to session mode + start recording. replay.flush(); } - setReplayId(replay.getReplayId()); // this will set isRecording + setSessionId(replay.getReplayId()); // this will set isRecording } }} > From 9246bacbccf66defcc94acb93fb3bdd480a77527 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:25:02 -0700 Subject: [PATCH 06/26] Add tooltip + some comments and cleanup --- .../components/replay/replayPanel.tsx | 138 +++++++++--------- 1 file changed, 70 insertions(+), 68 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 30991977a92a1c..da681ebea8ae31 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,4 +1,4 @@ -import {Fragment, useEffect, useState} from 'react'; +import {useEffect, useState} from 'react'; import {css} from '@emotion/react'; import type {ReplayRecordingMode} from '@sentry/types'; @@ -7,7 +7,6 @@ import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink import {resetFlexRowCss} from 'sentry/components/devtoolbar/styles/reset'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import {IconPause, IconPlay} from 'sentry/icons'; -import {t} from 'sentry/locale'; import type {PlatformKey} from 'sentry/types/project'; import useConfiguration from '../../hooks/useConfiguration'; @@ -61,74 +60,77 @@ export default function ReplayPanel() { return ( - - -
- {lastReplayId ? ( - - {isRecording ? t('Current replay: ') : t('Last recorded replay: ')} - { - trackAnalytics?.({ - eventKey: `devtoolbar.current-replay-link.click`, - eventName: `devtoolbar: Current replay link clicked`, - }); - }} + setSessionId(replay.getReplayId()); // this will set isRecording + } + }} + > + {isRecording + ? 'In progress. Click to stop recording' + : 'Start recording the current session'} + +
+ {lastReplayId ? ( + + {isRecording ? 'Current replay: ' : 'Last recorded replay: '} + { + trackAnalytics?.({ + eventKey: `devtoolbar.current-replay-link.click`, + eventName: `devtoolbar: Current replay link clicked`, + }); + }} + > +
-
- - {lastReplayId.slice(0, TRUNC_ID_LENGTH)} -
- - - ) : ( - 'No replay' - )} -
- + + {lastReplayId.slice(0, TRUNC_ID_LENGTH)} +
+
+
+ ) : ( + 'No replay is recording this session.' + )} +
); } From 3ba529b692ce3634779002152b9d6e3b6d73913a Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:58:03 -0700 Subject: [PATCH 07/26] Refactor all state and sdk calls to a context provider, and handle older versions w try-catch --- .../devtoolbar/components/providers.tsx | 9 +- .../components/replay/replayPanel.tsx | 66 +-------- .../devtoolbar/hooks/useReplayContext.tsx | 136 ++++++++++++++++++ static/app/components/devtoolbar/types.ts | 10 ++ 4 files changed, 159 insertions(+), 62 deletions(-) create mode 100644 static/app/components/devtoolbar/hooks/useReplayContext.tsx diff --git a/static/app/components/devtoolbar/components/providers.tsx b/static/app/components/devtoolbar/components/providers.tsx index 3ba29e36ad0512..56d574e13c11e5 100644 --- a/static/app/components/devtoolbar/components/providers.tsx +++ b/static/app/components/devtoolbar/components/providers.tsx @@ -3,6 +3,7 @@ import createCache from '@emotion/cache'; import {CacheProvider, ThemeProvider} from '@emotion/react'; import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; +import {ReplayContextProvider} from 'sentry/components/devtoolbar/hooks/useReplayContext'; import {lightTheme} from 'sentry/utils/theme'; import {ConfigurationContextProvider} from '../hooks/useConfiguration'; @@ -37,9 +38,11 @@ export default function Providers({children, config, container}: Props) { - - {children} - + + + {children} + + diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index da681ebea8ae31..aeaa1e954f6fae 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,9 +1,8 @@ -import {useEffect, useState} from 'react'; import {css} from '@emotion/react'; -import type {ReplayRecordingMode} from '@sentry/types'; import {Button} from 'sentry/components/button'; import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink'; +import useReplayContext from 'sentry/components/devtoolbar/hooks/useReplayContext'; import {resetFlexRowCss} from 'sentry/components/devtoolbar/styles/reset'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import {IconPause, IconPlay} from 'sentry/icons'; @@ -15,72 +14,21 @@ import {smallCss} from '../../styles/typography'; import PanelLayout from '../panelLayout'; const TRUNC_ID_LENGTH = 16; -const POLL_INTERVAL_MS = 3000; export default function ReplayPanel() { - const {projectSlug, projectId, projectPlatform, trackAnalytics, SentrySDK} = - useConfiguration(); - const replay = - SentrySDK && 'getReplay' in SentrySDK ? SentrySDK.getReplay() : undefined; + const {projectSlug, projectId, projectPlatform, trackAnalytics} = useConfiguration(); - // sessionId is undefined iff we are recording in session OR buffer mode. - const [sessionId, setSessionId] = useState(() => - replay?.getReplayId() - ); - const [recordingMode, setRecordingMode] = useState( - () => replay?._replay.recordingMode - ); - // Polls periodically since a replay could be started by sessionSampleRate - useEffect(() => { - const intervalId = setInterval(() => { - setSessionId(replay?.getReplayId()); - setRecordingMode(replay?._replay.recordingMode); - }, POLL_INTERVAL_MS); - return () => clearInterval(intervalId); - }, [replay]); - - const [isRecording, setIsRecording] = useState( - () => replay?.getReplayId() && replay?._replay.recordingMode === 'session' - ); - useEffect( - () => setIsRecording(sessionId && recordingMode === 'session'), - [sessionId, recordingMode] - ); - - // Used to persist the link to the last recorded replay, even if it's stopped. - // TODO: this is lost after leaving the panel. Could use a local storage? - const [lastReplayId, setLastReplayId] = useState(() => { - return recordingMode === 'session' ? replay?.getReplayId() : undefined; - }); - useEffect(() => { - if (sessionId && recordingMode === 'session') { - setLastReplayId(sessionId); - } - }, [sessionId, recordingMode]); + const {disabledReason, isDisabled, isRecording, lastReplayId, start, stop} = + useReplayContext(); return ( + +
{lastReplayId ? ( From 7f9903ed687c73ff97c5e565c57596d96372a720 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:12:16 -0700 Subject: [PATCH 16/26] Rm sdk debug flag --- static/app/bootstrap/initializeSdk.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/app/bootstrap/initializeSdk.tsx b/static/app/bootstrap/initializeSdk.tsx index f5999191713d3c..a1c09c2dc1d49f 100644 --- a/static/app/bootstrap/initializeSdk.tsx +++ b/static/app/bootstrap/initializeSdk.tsx @@ -175,8 +175,6 @@ export function initializeSdk(config: Config, {routes}: {routes?: Function} = {} return event; }, - - debug: true, }); if (process.env.NODE_ENV !== 'production') { From 608e1133157c13787d2944162b2b5e6e3847d901 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:13:38 -0700 Subject: [PATCH 17/26] Refactor private API function calls --- .../devtoolbar/hooks/useReplayRecorder.tsx | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index 2e0ed58a601ed3..5c0a1f112e55bf 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -13,41 +13,37 @@ type ReplayRecorderState = { stop(): Promise; }; -function getIsRecording( - replay: ReturnType | undefined -): boolean { - return replay?._replay.isEnabled() ?? false; +interface ReplayInternalAPI { + [other: string]: any; + getSessionId(): string | undefined; + isEnabled(): boolean; + recordingMode: ReplayRecordingMode; } -function getSessionId( - replay: ReturnType | undefined -): string | undefined { - return replay?._replay.getSessionId(); -} - -function getRecordingMode( - replay: ReturnType | undefined -): ReplayRecordingMode | undefined { - return replay?._replay.recordingMode; +function getReplayInternal( + replay: ReturnType +): ReplayInternalAPI { + // While the toolbar is internal, we can use the private API for added functionality and reduced dependence on SDK release versions + // @ts-ignore:next-line + return replay._replay; } const LAST_REPLAY_STORAGE_KEY = 'devtoolbar.last_replay_id'; export default function useReplayRecorder(): ReplayRecorderState { - // INTERNAL STATE const {SentrySDK} = useConfiguration(); const replay = SentrySDK && 'getReplay' in SentrySDK ? SentrySDK.getReplay() : undefined; + const replayInternal = replay ? getReplayInternal(replay) : undefined; // sessionId is defined if we are recording in session OR buffer mode. const [sessionId, setSessionId] = useState(() => - getSessionId(replay) + replayInternal?.getSessionId() ); const [recordingMode, setRecordingMode] = useState( - () => getRecordingMode(replay) + () => replayInternal?.recordingMode ); - // EXPORTED const isDisabled = replay === undefined; const disabledReason = !SentrySDK ? 'Failed to load the Sentry SDK.' @@ -57,9 +53,11 @@ export default function useReplayRecorder(): ReplayRecorderState { ? "Failed to load your SDK's Replay integration." : undefined; - const [isRecording, setIsRecording] = useState(false); + const [isRecording, setIsRecording] = useState( + () => replayInternal?.isEnabled() ?? false + ); const [lastReplayId, setLastReplayId] = useState( - sessionStorage.getItem(LAST_REPLAY_STORAGE_KEY) || undefined + () => sessionStorage.getItem(LAST_REPLAY_STORAGE_KEY) || undefined ); useEffect(() => { if (isRecording && sessionId) { @@ -69,10 +67,10 @@ export default function useReplayRecorder(): ReplayRecorderState { }, [isRecording, sessionId]); const refreshState = useCallback(() => { - setIsRecording(getIsRecording(replay)); - setSessionId(getSessionId(replay)); - setRecordingMode(getRecordingMode(replay)); - }, [replay]); + setIsRecording(replayInternal?.isEnabled() ?? false); + setSessionId(replayInternal?.getSessionId()); + setRecordingMode(replayInternal?.recordingMode); + }, [replayInternal]); const start = useCallback(async () => { let success = false; From 1276d6b5b357520ac17da08164f07ed968d5ccc2 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:18:40 -0700 Subject: [PATCH 18/26] Move analytics provider --- .../components/replay/replayPanel.tsx | 100 ++++++++++-------- .../devtoolbar/components/sentryAppLink.tsx | 3 + 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 4d074c0f4dc381..1a47f227bd1111 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,7 +1,10 @@ +import {useContext} from 'react'; import {css} from '@emotion/react'; import {Button} from 'sentry/components/button'; -import AnalyticsProvider from 'sentry/components/devtoolbar/components/analyticsProvider'; +import AnalyticsProvider, { + AnalyticsContext, +} from 'sentry/components/devtoolbar/components/analyticsProvider'; import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink'; import useReplayRecorder from 'sentry/components/devtoolbar/hooks/useReplayRecorder'; import {resetFlexRowCss} from 'sentry/components/devtoolbar/styles/reset'; @@ -18,31 +21,34 @@ import PanelLayout from '../panelLayout'; const TRUNC_ID_LENGTH = 16; export default function ReplayPanel() { - const {projectSlug, projectId, projectPlatform} = useConfiguration(); + const {projectSlug, projectId, projectPlatform, trackAnalytics} = useConfiguration(); const {disabledReason, isDisabled, isRecording, lastReplayId, start, stop} = useReplayRecorder(); function ReplayLink({children}: {children: React.ReactNode}) { - return ( - - {process.env.NODE_ENV === 'production' ? ( - - {children} - - ) : ( - - {children} - - )} - + const {eventName, eventKey} = useContext(AnalyticsContext); + return process.env.NODE_ENV === 'production' ? ( + + {children} + + ) : ( + { + trackAnalytics?.({ + eventKey: eventKey + '.click', + eventName: eventName + ' clicked', + }); + }} + > + {children} + ); } @@ -68,31 +74,33 @@ export default function ReplayPanel() { {lastReplayId ? ( {isRecording ? 'Current replay: ' : 'Last recorded replay: '} - -
- - {lastReplayId.slice(0, TRUNC_ID_LENGTH)} -
-
+ + +
+ + {lastReplayId.slice(0, TRUNC_ID_LENGTH)} +
+
+
) : ( 'No replay is recording this session.' diff --git a/static/app/components/devtoolbar/components/sentryAppLink.tsx b/static/app/components/devtoolbar/components/sentryAppLink.tsx index 1d86f873dae5ff..7a5fe65048a5c8 100644 --- a/static/app/components/devtoolbar/components/sentryAppLink.tsx +++ b/static/app/components/devtoolbar/components/sentryAppLink.tsx @@ -12,6 +12,9 @@ interface Props { onClick?: (event: MouseEvent) => void; } +/** + * Inline link to orgSlug.sentry.io/{to} with built-in click analytic. + */ export default function SentryAppLink({children, to}: Props) { const {organizationSlug, trackAnalytics} = useConfiguration(); const {eventName, eventKey} = useContext(AnalyticsContext); From 7f99b48410b62254fe2e13afee35dc0b67e60de9 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 5 Aug 2024 23:10:03 -0700 Subject: [PATCH 19/26] Address review comments and track button failures --- .../components/replay/replayPanel.tsx | 133 +++++++++--------- .../devtoolbar/hooks/useReplayRecorder.tsx | 9 +- static/app/utils/useDevToolbar.tsx | 8 +- 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 1a47f227bd1111..29bace1dbbc207 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -1,4 +1,4 @@ -import {useContext} from 'react'; +import {useContext, useState} from 'react'; import {css} from '@emotion/react'; import {Button} from 'sentry/components/button'; @@ -9,7 +9,6 @@ import SentryAppLink from 'sentry/components/devtoolbar/components/sentryAppLink import useReplayRecorder from 'sentry/components/devtoolbar/hooks/useReplayRecorder'; import {resetFlexRowCss} from 'sentry/components/devtoolbar/styles/reset'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; -import ExternalLink from 'sentry/components/links/externalLink'; import {IconPause, IconPlay} from 'sentry/icons'; import type {PlatformKey} from 'sentry/types/project'; @@ -21,85 +20,47 @@ import PanelLayout from '../panelLayout'; const TRUNC_ID_LENGTH = 16; export default function ReplayPanel() { - const {projectSlug, projectId, projectPlatform, trackAnalytics} = useConfiguration(); + const {trackAnalytics} = useConfiguration(); const {disabledReason, isDisabled, isRecording, lastReplayId, start, stop} = useReplayRecorder(); - function ReplayLink({children}: {children: React.ReactNode}) { - const {eventName, eventKey} = useContext(AnalyticsContext); - return process.env.NODE_ENV === 'production' ? ( - - {children} - - ) : ( - { + const {eventName, eventKey} = useContext(AnalyticsContext); + const [buttonLoading, setButtonLoading] = useState(false); + return ( + + - + {isRecording + ? 'In progress. Click to stop recording' + : 'Start recording the current session'} +
{lastReplayId ? ( {isRecording ? 'Current replay: ' : 'Last recorded replay: '} - -
- - {lastReplayId.slice(0, TRUNC_ID_LENGTH)} -
-
+
) : ( @@ -109,3 +70,39 @@ export default function ReplayPanel() { ); } + +function ReplayLink({lastReplayId}: {lastReplayId: string}) { + const {projectSlug, projectId, projectPlatform} = useConfiguration(); + return ( + +
+ + {lastReplayId.slice(0, TRUNC_ID_LENGTH)} +
+
+ ); +} diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index 5c0a1f112e55bf..7fb9e3c086a21a 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -3,6 +3,7 @@ import type {replayIntegration} from '@sentry/react'; import type {ReplayRecordingMode} from '@sentry/types'; import useConfiguration from 'sentry/components/devtoolbar/hooks/useConfiguration'; +import {useSessionStorage} from 'sentry/utils/useSessionStorage'; type ReplayRecorderState = { disabledReason: string | undefined; @@ -56,15 +57,15 @@ export default function useReplayRecorder(): ReplayRecorderState { const [isRecording, setIsRecording] = useState( () => replayInternal?.isEnabled() ?? false ); - const [lastReplayId, setLastReplayId] = useState( - () => sessionStorage.getItem(LAST_REPLAY_STORAGE_KEY) || undefined + const [lastReplayId, setLastReplayId] = useSessionStorage( + LAST_REPLAY_STORAGE_KEY, + undefined ); useEffect(() => { if (isRecording && sessionId) { setLastReplayId(sessionId); - sessionStorage.setItem(LAST_REPLAY_STORAGE_KEY, sessionId); } - }, [isRecording, sessionId]); + }, [isRecording, sessionId, setLastReplayId]); const refreshState = useCallback(() => { setIsRecording(replayInternal?.isEnabled() ?? false); diff --git a/static/app/utils/useDevToolbar.tsx b/static/app/utils/useDevToolbar.tsx index beb2c345a3f797..791a10174187d9 100644 --- a/static/app/utils/useDevToolbar.tsx +++ b/static/app/utils/useDevToolbar.tsx @@ -25,10 +25,12 @@ export default function useDevToolbar({enabled}: {enabled: boolean}) { SentrySDK: Sentry, apiPrefix, environment: ['prod'], - organizationSlug: 'sentry', - projectId: 11276, + organizationSlug: + process.env.NODE_ENV !== 'development' ? 'sentry' : 'sentry-test', + projectId: process.env.NODE_ENV !== 'development' ? 11276 : 5270453, projectPlatform: 'javascript', - projectSlug: 'javascript', + projectSlug: + process.env.NODE_ENV !== 'development' ? 'javascript' : 'app-frontend', featureFlags: { getFeatureFlagMap: () => FeatureFlagOverrides.singleton().getFeatureFlagMap(organization), From f30b5a9f0403dfc0f6f3d52847182b1822477d9e Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:02:00 -0700 Subject: [PATCH 20/26] Undo package.json formatting --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d60643156f34aa..efa272742ded15 100644 --- a/package.json +++ b/package.json @@ -263,7 +263,9 @@ "last 3 iOS major versions", "Firefox ESR" ], - "test": ["current node"] + "test": [ + "current node" + ] }, "volta": { "extends": ".volta.json" From 44ed001bfa77ff82e4df0ae641ab80db149dd181 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:12:40 -0700 Subject: [PATCH 21/26] Update button label + url --- .../components/devtoolbar/components/replay/replayPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 29bace1dbbc207..ed7d36df080e7b 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -52,7 +52,7 @@ export default function ReplayPanel() { }} > {isRecording - ? 'In progress. Click to stop recording' + ? 'Recording in progress, click to stop' : 'Start recording the current session'}
@@ -76,7 +76,7 @@ function ReplayLink({lastReplayId}: {lastReplayId: string}) { return ( From bd0d0efdbbde821a667a20ca5ab8ce8ff25ad6a0 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:13:25 -0700 Subject: [PATCH 22/26] Ref start/stop to use finally --- .../devtoolbar/hooks/useReplayRecorder.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index 7fb9e3c086a21a..bd59d58bfb8340 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -75,10 +75,10 @@ export default function useReplayRecorder(): ReplayRecorderState { const start = useCallback(async () => { let success = false; - if (replay && !isRecording) { - try { - // SDK v8.19.0 and older will throw if a replay is already started. - // Details at https://github.com/getsentry/sentry-javascript/pull/13000 + try { + // SDK v8.19.0 and older will throw if a replay is already started. + // Details at https://github.com/getsentry/sentry-javascript/pull/13000 + if (replay && !isRecording) { if (recordingMode === 'session') { replay.start(); } else { @@ -86,24 +86,28 @@ export default function useReplayRecorder(): ReplayRecorderState { await replay.flush(); } success = true; - // eslint-disable-next-line no-empty - } catch {} + } + // eslint-disable-next-line no-empty + } catch { + } finally { + refreshState(); + return success; } - refreshState(); - return success; }, [isRecording, recordingMode, replay, refreshState]); const stop = useCallback(async () => { let success = false; - if (replay && isRecording) { - try { + try { + if (replay && isRecording) { await replay.stop(); success = true; - // eslint-disable-next-line no-empty - } catch {} + } + // eslint-disable-next-line no-empty + } catch { + } finally { + refreshState(); + return success; } - refreshState(); - return success; }, [isRecording, replay, refreshState]); return { From bcd8f25d223fbea9e727d7b18ed0c1b48fdf3f33 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:23:16 -0700 Subject: [PATCH 23/26] Update disabled msgs to show in button, instead of tooltip --- .../devtoolbar/components/replay/replayPanel.tsx | 11 ++++++----- .../components/devtoolbar/hooks/useReplayRecorder.tsx | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index ed7d36df080e7b..9b76aa68df8937 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -31,9 +31,8 @@ export default function ReplayPanel() {
{lastReplayId ? ( diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index bd59d58bfb8340..42eec95e207929 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -49,7 +49,7 @@ export default function useReplayRecorder(): ReplayRecorderState { const disabledReason = !SentrySDK ? 'Failed to load the Sentry SDK.' : !('getReplay' in SentrySDK) - ? 'Your SDK version is too outdated to use the Replay integration.' + ? 'Your SDK version is too old to support Replays.' : !replay ? "Failed to load your SDK's Replay integration." : undefined; From 697a09af20367648e76b93caf36c5f61867f59a5 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:29:18 -0700 Subject: [PATCH 24/26] Update missing integration msg --- static/app/components/devtoolbar/hooks/useReplayRecorder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index 42eec95e207929..1a7c9a2d2455c4 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -51,7 +51,7 @@ export default function useReplayRecorder(): ReplayRecorderState { : !('getReplay' in SentrySDK) ? 'Your SDK version is too old to support Replays.' : !replay - ? "Failed to load your SDK's Replay integration." + ? 'You need to install the SDK Replay integration.' : undefined; const [isRecording, setIsRecording] = useState( From b9fc69c1bc7d13ff6b347ec6d9c50b5b6430347e Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:46:53 -0700 Subject: [PATCH 25/26] Fix broken buffer case, update buffer label and rm try-catch --- .../components/replay/replayPanel.tsx | 30 +++++----- .../devtoolbar/hooks/useReplayRecorder.tsx | 55 ++++++++----------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/static/app/components/devtoolbar/components/replay/replayPanel.tsx b/static/app/components/devtoolbar/components/replay/replayPanel.tsx index 9b76aa68df8937..2c0e3486d2ce4d 100644 --- a/static/app/components/devtoolbar/components/replay/replayPanel.tsx +++ b/static/app/components/devtoolbar/components/replay/replayPanel.tsx @@ -22,8 +22,16 @@ const TRUNC_ID_LENGTH = 16; export default function ReplayPanel() { const {trackAnalytics} = useConfiguration(); - const {disabledReason, isDisabled, isRecording, lastReplayId, start, stop} = - useReplayRecorder(); + const { + disabledReason, + isDisabled, + isRecording, + lastReplayId, + recordingMode, + startRecordingSession, + stopRecording, + } = useReplayRecorder(); + const isRecordingSession = isRecording && recordingMode === 'session'; const {eventName, eventKey} = useContext(AnalyticsContext); const [buttonLoading, setButtonLoading] = useState(false); @@ -31,30 +39,26 @@ export default function ReplayPanel() {
{lastReplayId ? ( diff --git a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx index 1a7c9a2d2455c4..70d1be99034da1 100644 --- a/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx +++ b/static/app/components/devtoolbar/hooks/useReplayRecorder.tsx @@ -10,8 +10,9 @@ type ReplayRecorderState = { isDisabled: boolean; isRecording: boolean; lastReplayId: string | undefined; - start(): Promise; - stop(): Promise; + recordingMode: ReplayRecordingMode | undefined; + startRecordingSession(): Promise; // returns false if called in the wrong state + stopRecording(): Promise; // returns false if called in the wrong state }; interface ReplayInternalAPI { @@ -62,10 +63,10 @@ export default function useReplayRecorder(): ReplayRecorderState { undefined ); useEffect(() => { - if (isRecording && sessionId) { + if (isRecording && recordingMode === 'session' && sessionId) { setLastReplayId(sessionId); } - }, [isRecording, sessionId, setLastReplayId]); + }, [isRecording, recordingMode, sessionId, setLastReplayId]); const refreshState = useCallback(() => { setIsRecording(replayInternal?.isEnabled() ?? false); @@ -73,41 +74,32 @@ export default function useReplayRecorder(): ReplayRecorderState { setRecordingMode(replayInternal?.recordingMode); }, [replayInternal]); - const start = useCallback(async () => { + const startRecordingSession = useCallback(async () => { let success = false; - try { - // SDK v8.19.0 and older will throw if a replay is already started. + if (replay) { + // Note SDK v8.19 and older will throw if a replay is already started. // Details at https://github.com/getsentry/sentry-javascript/pull/13000 - if (replay && !isRecording) { - if (recordingMode === 'session') { - replay.start(); - } else { - // For SDK v8.20.0 and up, flush() works for both cases. - await replay.flush(); - } + if (!isRecording) { + replay.start(); + success = true; + } else if (recordingMode === 'buffer') { + // For SDK v8.20+, flush() would work for both cases, but we're staying version-agnostic. + await replay.flush(); success = true; } - // eslint-disable-next-line no-empty - } catch { - } finally { refreshState(); - return success; } - }, [isRecording, recordingMode, replay, refreshState]); + return success; + }, [replay, isRecording, recordingMode, refreshState]); - const stop = useCallback(async () => { + const stopRecording = useCallback(async () => { let success = false; - try { - if (replay && isRecording) { - await replay.stop(); - success = true; - } - // eslint-disable-next-line no-empty - } catch { - } finally { + if (replay && isRecording) { + await replay.stop(); + success = true; refreshState(); - return success; } + return success; }, [isRecording, replay, refreshState]); return { @@ -115,7 +107,8 @@ export default function useReplayRecorder(): ReplayRecorderState { isDisabled, isRecording, lastReplayId, - start, - stop, + recordingMode, + startRecordingSession, + stopRecording, }; } From 87ab1ded65636830bdd315b6034a461e1c5dde7e Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:48:39 -0700 Subject: [PATCH 26/26] Revert useDevToolbar --- static/app/utils/useDevToolbar.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/static/app/utils/useDevToolbar.tsx b/static/app/utils/useDevToolbar.tsx index 791a10174187d9..beb2c345a3f797 100644 --- a/static/app/utils/useDevToolbar.tsx +++ b/static/app/utils/useDevToolbar.tsx @@ -25,12 +25,10 @@ export default function useDevToolbar({enabled}: {enabled: boolean}) { SentrySDK: Sentry, apiPrefix, environment: ['prod'], - organizationSlug: - process.env.NODE_ENV !== 'development' ? 'sentry' : 'sentry-test', - projectId: process.env.NODE_ENV !== 'development' ? 11276 : 5270453, + organizationSlug: 'sentry', + projectId: 11276, projectPlatform: 'javascript', - projectSlug: - process.env.NODE_ENV !== 'development' ? 'javascript' : 'app-frontend', + projectSlug: 'javascript', featureFlags: { getFeatureFlagMap: () => FeatureFlagOverrides.singleton().getFeatureFlagMap(organization),