From 0dac3371f66331a1e1909e6fec42f6efb5f2a023 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Wed, 14 Aug 2024 11:13:41 -0400 Subject: [PATCH] refactor(app): consolidate initialAction and errorEvent recovery analytics (#15992) --- .../ErrorRecoveryFlows/RunPausedSplash.tsx | 6 ++--- .../ErrorRecoveryFlows/__fixtures__/index.ts | 1 - .../__tests__/ErrorRecoveryFlows.test.tsx | 19 --------------- .../ErrorRecoveryFlows/hooks/useERUtils.ts | 7 ++++-- .../hooks/useRecoveryAnalytics.ts | 24 +++++++------------ .../organisms/ErrorRecoveryFlows/index.tsx | 9 ------- app/src/redux/analytics/constants.ts | 1 - 7 files changed, 17 insertions(+), 50 deletions(-) diff --git a/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx b/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx index 6d2d6d5d836..a56b4eb16d5 100644 --- a/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx @@ -78,7 +78,7 @@ export function RunPausedSplash( const title = useErrorName(errorKind) const { proceedToRouteAndStep } = routeUpdateActions - const { reportInitialActionEvent } = analytics + const { reportErrorEvent } = analytics const buildTitleHeadingDesktop = (): JSX.Element => { return ( @@ -91,14 +91,14 @@ export function RunPausedSplash( // Do not launch error recovery, but do utilize the wizard's cancel route. const onCancelClick = (): Promise => { return toggleERWizAsActiveUser(true, false).then(() => { - reportInitialActionEvent('cancel-run') + reportErrorEvent(failedCommand?.byRunRecord ?? null, 'cancel-run') void proceedToRouteAndStep(RECOVERY_MAP.CANCEL_RUN.ROUTE) }) } const onLaunchERClick = (): Promise => { return toggleERWizAsActiveUser(true, true).then(() => { - reportInitialActionEvent('launch-recovery') + reportErrorEvent(failedCommand?.byRunRecord ?? null, 'launch-recovery') }) } diff --git a/app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts b/app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts index cfc51ef036c..129b2554ca5 100644 --- a/app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts +++ b/app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts @@ -90,7 +90,6 @@ export const mockRecoveryContentProps: RecoveryContentProps = { reportErrorEvent: () => {}, reportViewErrorDetailsEvent: () => {}, reportActionSelectedEvent: () => {}, - reportInitialActionEvent: () => {}, reportActionSelectedResult: () => {}, }, } diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx index 3ab9e368810..8ed839887ef 100644 --- a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx @@ -206,23 +206,4 @@ describe('ErrorRecoveryFlows', () => { render(props) expect(screen.queryByText('MOCK RUN PAUSED SPLASH')).not.toBeInTheDocument() }) - - it('calls reportErrorEvent with failedCommand on mount and when failedCommand changes', () => { - const mockReportErrorEvent = vi.fn() - vi.mocked(useRecoveryAnalytics).mockReturnValue({ - reportErrorEvent: mockReportErrorEvent, - } as any) - - const { rerender } = render(props) - expect(mockReportErrorEvent).toHaveBeenCalledWith(mockFailedCommand) - - const newProps = { - ...props, - failedCommandByRunRecord: null, - } - rerender() - expect(mockReportErrorEvent).toHaveBeenCalledWith( - newProps.failedCommandByRunRecord - ) - }) }) diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts index 5833a0a2dd8..274c8d54eb4 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts @@ -15,6 +15,7 @@ import { useRecoveryOptionCopy } from './useRecoveryOptionCopy' import { useRecoveryActionMutation } from './useRecoveryActionMutation' import { useRunningStepCounts } from '../../../resources/protocols/hooks' import { useRecoveryToasts } from './useRecoveryToasts' +import { useRecoveryAnalytics } from './useRecoveryAnalytics' import type { PipetteData } from '@opentrons/api-client' import type { RobotType } from '@opentrons/shared-data' @@ -40,7 +41,6 @@ export type ERUtilsProps = Omit & { hasLaunchedRecovery: boolean isOnDevice: boolean robotType: RobotType - analytics: UseRecoveryAnalyticsResult failedCommand: ReturnType } @@ -59,6 +59,7 @@ export interface ERUtilsResults { stepCounts: StepCounts commandsAfterFailedCommand: ReturnType subMapUtils: SubMapUtils + analytics: UseRecoveryAnalyticsResult } const SUBSEQUENT_COMMAND_DEPTH = 2 @@ -71,7 +72,6 @@ export function useERUtils({ protocolAnalysis, isOnDevice, robotType, - analytics, }: ERUtilsProps): ERUtilsResults { const { data: attachedInstruments } = useInstrumentsQuery() const { data: runRecord } = useNotifyRunQuery(runId) @@ -88,6 +88,8 @@ export function useERUtils({ const stepCounts = useRunningStepCounts(runId, runCommands) + const analytics = useRecoveryAnalytics() + const { recoveryMap, setRM, @@ -172,5 +174,6 @@ export function useERUtils({ getRecoveryOptionCopy, stepCounts, commandsAfterFailedCommand, + analytics, } } diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts index a94c8f290ad..3a069284240 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts @@ -4,7 +4,6 @@ import { ANALYTICS_RECOVERY_ACTION_RESULT, ANALYTICS_RECOVERY_ACTION_SELECTED, ANALYTICS_RECOVERY_ERROR_EVENT, - ANALYTICS_RECOVERY_INITIAL_ACTION, ANALYTICS_RECOVERY_RUN_RESULT, ANALYTICS_RECOVERY_VIEW_ERROR_DETAILS, useTrackEvent, @@ -18,9 +17,10 @@ type CommandResult = 'succeeded' | 'failed' export interface UseRecoveryAnalyticsResult { /* Report the error which occurs error recovery is currently handling. */ - reportErrorEvent: (failedCommand: FailedCommand | null) => void - /* Report which action the user selected on the recovery splash screen. */ - reportInitialActionEvent: (initialAction: InitialActionType) => void + reportErrorEvent: ( + failedCommand: FailedCommand | null, + initialAction: InitialActionType + ) => void /* Report which recovery option the user selected. */ reportActionSelectedEvent: (selectedRecoveryOption: RecoveryRoute) => void /* Report when the user views the error details and where they currently are in Error Recovery. */ @@ -40,27 +40,22 @@ export interface UseRecoveryAnalyticsResult { export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { const doTrackEvent = useTrackEvent() - const reportErrorEvent = (failedCommand: FailedCommand | null): void => { + const reportErrorEvent = ( + failedCommand: FailedCommand | null, + initialAction: InitialActionType + ): void => { if (failedCommand != null) { doTrackEvent({ name: ANALYTICS_RECOVERY_ERROR_EVENT, properties: { errorEvent: failedCommand.commandType, errorString: failedCommand.error?.detail, + initialAction, }, }) } } - const reportInitialActionEvent = (initialAction: InitialActionType): void => { - doTrackEvent({ - name: ANALYTICS_RECOVERY_INITIAL_ACTION, - properties: { - initialAction, - }, - }) - } - const reportActionSelectedEvent = ( selectedRecoveryOption: RecoveryRoute ): void => { @@ -120,7 +115,6 @@ export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { reportActionSelectedEvent, reportActionSelectedResult, reportErrorEvent, - reportInitialActionEvent, reportViewErrorDetailsEvent, reportRecoveredRunResult, } diff --git a/app/src/organisms/ErrorRecoveryFlows/index.tsx b/app/src/organisms/ErrorRecoveryFlows/index.tsx index 4986197e9d0..bb5dd9af584 100644 --- a/app/src/organisms/ErrorRecoveryFlows/index.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/index.tsx @@ -23,7 +23,6 @@ import { RecoveryTakeover } from './RecoveryTakeover' import { useCurrentlyRecoveringFrom, useERUtils, - useRecoveryAnalytics, useRecoveryTakeover, useRetainedFailedCommandBySource, useShowDoorInfo, @@ -124,11 +123,6 @@ export function ErrorRecoveryFlows( protocolAnalysis ) - const analytics = useRecoveryAnalytics() - React.useEffect(() => { - analytics.reportErrorEvent(failedCommandByRunRecord) - }, [failedCommandByRunRecord?.error?.detail]) - const { hasLaunchedRecovery, toggleERWizard, showERWizard } = useERWizard() const isOnDevice = useSelector(getIsOnDevice) const robotType = protocolAnalysis?.robotType ?? OT2_ROBOT_TYPE @@ -150,7 +144,6 @@ export function ErrorRecoveryFlows( toggleERWizAsActiveUser, isOnDevice, robotType, - analytics, failedCommand: failedCommandBySource, }) @@ -171,7 +164,6 @@ export function ErrorRecoveryFlows( robotType={robotType} isOnDevice={isOnDevice} isDoorOpen={isDoorOpen} - analytics={analytics} failedCommand={failedCommandBySource} /> ) : null} @@ -183,7 +175,6 @@ export function ErrorRecoveryFlows( robotName={robotName} isOnDevice={isOnDevice} toggleERWizAsActiveUser={toggleERWizAsActiveUser} - analytics={analytics} failedCommand={failedCommandBySource} /> ) : null} diff --git a/app/src/redux/analytics/constants.ts b/app/src/redux/analytics/constants.ts index e2dc4d58473..18e10cc8be8 100644 --- a/app/src/redux/analytics/constants.ts +++ b/app/src/redux/analytics/constants.ts @@ -66,7 +66,6 @@ export const ANALYTICS_ROBOT_UPDATE_CHANGE_LOG_VIEW = 'robotUpdateChangeLogView' */ export const ANALYTICS_RECOVERY_ERROR_EVENT = 'recoveryErrorEvent' -export const ANALYTICS_RECOVERY_INITIAL_ACTION = 'recoveryInitialAction' export const ANALYTICS_RECOVERY_ACTION_SELECTED = 'recoverySelectedRecoveryAction' export const ANALYTICS_RECOVERY_VIEW_ERROR_DETAILS = 'recoveryViewErrorDetails'