diff --git a/app/src/organisms/ChooseProtocolSlideout/index.tsx b/app/src/organisms/ChooseProtocolSlideout/index.tsx index 2b928495a7b..e1dada9d64a 100644 --- a/app/src/organisms/ChooseProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/index.tsx @@ -82,7 +82,8 @@ export function ChooseProtocolSlideoutComponent( : [] const { trackCreateProtocolRunEvent } = useTrackCreateProtocolRunEvent( - selectedProtocol + selectedProtocol, + name ) const { diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx index c4e50fc5a88..b2215914088 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx @@ -49,11 +49,12 @@ export function ChooseRobotToRunProtocolSlideoutComponent( mostRecentAnalysis, } = storedProtocolData + const [selectedRobot, setSelectedRobot] = React.useState(null) const { trackCreateProtocolRunEvent } = useTrackCreateProtocolRunEvent( - storedProtocolData + storedProtocolData, + selectedRobot?.name ?? '' ) - const [selectedRobot, setSelectedRobot] = React.useState(null) const offsetCandidates = useOffsetCandidatesForAnalysis( mostRecentAnalysis, selectedRobot?.ip ?? null diff --git a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx index 440c371ec53..bf06e0db263 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx @@ -129,7 +129,7 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element { closeOverflowMenu(e) } const trackEvent = useTrackEvent() - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const { reset } = useRunControls(runId, onResetSuccess) const { deleteRun } = useDeleteRunMutation() diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx index d12da9838cf..e299657fe05 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx @@ -155,7 +155,7 @@ export function ProtocolRunHeader({ isProtocolAnalyzing, } = useProtocolDetailsForRun(runId) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const robotAnalyticsData = useRobotAnalyticsData(robotName) const isRobotViewable = useIsRobotViewable(robotName) const runStatus = useRunStatus(runId) @@ -453,6 +453,7 @@ export function ProtocolRunHeader({ setShowConfirmCancelModal(false)} runId={runId} + robotName={robotName} /> ) : null} {showDropTipWizard && @@ -575,7 +576,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { enabled: runStatus != null && START_RUN_STATUSES.includes(runStatus), })?.data?.data ?? [] const trackEvent = useTrackEvent() - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const [targetProps, tooltipProps] = useHoverTooltip() const { play, diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx index 5453af0efd9..2b0a2813660 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx @@ -406,9 +406,11 @@ describe('ProtocolRunHeader', () => { when(mockUseProtocolDetailsForRun) .calledWith(RUN_ID) .mockReturnValue(PROTOCOL_DETAILS) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) when(mockUseDismissCurrentRunMutation) .calledWith() .mockReturnValue({ diff --git a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx index 0939700387e..12461640384 100644 --- a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx +++ b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx @@ -106,9 +106,11 @@ describe('HistoricalProtocolRunOverflowMenu', () => { deleteRun: jest.fn(), } as any) ) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) when(mockUseRunControls) .calledWith(RUN_ID, expect.anything()) .mockReturnValue({ diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx index 0cfbb7fce93..554a1952c66 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx @@ -45,6 +45,7 @@ let store: Store = createStore(jest.fn(), {}) const RUN_ID = '1' const RUN_ID_2 = '2' +const ROBOT_NAME = 'otie' const PIPETTES = [ { id: '1', pipetteName: 'testModelLeft' }, @@ -111,9 +112,12 @@ describe('useProtocolAnalysisErrors hook', () => { }) it('returns getProtocolRunAnalyticsData function', () => { - const { result } = renderHook(() => useProtocolRunAnalyticsData(RUN_ID), { - wrapper, - }) + const { result } = renderHook( + () => useProtocolRunAnalyticsData(RUN_ID, ROBOT_NAME), + { + wrapper, + } + ) expect(typeof result.current.getProtocolRunAnalyticsData).toEqual( 'function' ) @@ -123,9 +127,12 @@ describe('useProtocolAnalysisErrors hook', () => { when(mockUseProtocolDetailsForRun) .calledWith(RUN_ID_2) .mockReturnValue({ protocolData: ROBOT_PROTOCOL_ANALYSIS } as any) - const { result } = renderHook(() => useProtocolRunAnalyticsData(RUN_ID_2), { - wrapper, - }) + const { result } = renderHook( + () => useProtocolRunAnalyticsData(RUN_ID_2, ROBOT_NAME), + { + wrapper, + } + ) const protocolRunAnalyticsData = await waitFor(() => result.current.getProtocolRunAnalyticsData() ) @@ -142,15 +149,19 @@ describe('useProtocolAnalysisErrors hook', () => { protocolText: 'hashedString', protocolType: '', robotType: 'OT-2 Standard', + robotSerialNumber: '', }, runTime: '1:00:00', }) }) it('getProtocolRunAnalyticsData returns fallback stored data when robot data unavailable', async () => { - const { result } = renderHook(() => useProtocolRunAnalyticsData(RUN_ID), { - wrapper, - }) + const { result } = renderHook( + () => useProtocolRunAnalyticsData(RUN_ID, ROBOT_NAME), + { + wrapper, + } + ) const protocolRunAnalyticsData = await waitFor(() => result.current.getProtocolRunAnalyticsData() ) @@ -167,6 +178,7 @@ describe('useProtocolAnalysisErrors hook', () => { protocolText: 'hashedString', protocolType: 'json', robotType: 'OT-2 Standard', + robotSerialNumber: '', }, runTime: '1:00:00', }) diff --git a/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx index 9719675a9f4..ead00dac63f 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx @@ -9,9 +9,12 @@ import { useRobot } from '../' import { useRobotAnalyticsData } from '../useRobotAnalyticsData' import { getAttachedPipettes } from '../../../../redux/pipettes' import { getRobotSettings } from '../../../../redux/robot-settings' +import { mockConnectableRobot } from '../../../../redux/discovery/__fixtures__' + import { getRobotApiVersion, getRobotFirmwareVersion, + getRobotSerialNumber, } from '../../../../redux/discovery' import type { DiscoveredRobot } from '../../../../redux/discovery/types' @@ -36,6 +39,9 @@ const mockGetRobotFirmwareVersion = getRobotFirmwareVersion as jest.MockedFuncti const mockGetAttachedPipettes = getAttachedPipettes as jest.MockedFunction< typeof getAttachedPipettes > +const mockGetRobotSerialNumber = getRobotSerialNumber as jest.MockedFunction< + typeof getRobotSerialNumber +> const ROBOT_SETTINGS = [ { id: `setting1`, value: true, title: '', description: '' }, @@ -47,6 +53,7 @@ const ATTACHED_PIPETTES = { left: { id: '1', model: 'testModelLeft' }, right: { id: '2', model: 'testModelRight' }, } +const ROBOT_SERIAL_NUMBER = 'OT123' let wrapper: React.FunctionComponent<{ children: React.ReactNode }> let store: Store = createStore(jest.fn(), {}) @@ -70,6 +77,7 @@ describe('useProtocolAnalysisErrors hook', () => { mockGetAttachedPipettes.mockReturnValue( ATTACHED_PIPETTES as AttachedPipettesByMount ) + mockGetRobotSerialNumber.mockReturnValue(ROBOT_SERIAL_NUMBER) }) afterEach(() => { @@ -87,7 +95,13 @@ describe('useProtocolAnalysisErrors hook', () => { it('returns robot analytics data when robot exists', () => { when(mockUseRobot) .calledWith('otie') - .mockReturnValue({} as DiscoveredRobot) + .mockReturnValue({ + ...mockConnectableRobot, + health: { + ...mockConnectableRobot.health, + robot_serial: ROBOT_SERIAL_NUMBER, + }, + } as DiscoveredRobot) const { result } = renderHook(() => useRobotAnalyticsData('otie'), { wrapper, @@ -99,6 +113,7 @@ describe('useProtocolAnalysisErrors hook', () => { robotLeftPipette: 'testModelLeft', robotRightPipette: 'testModelRight', robotSmoothieVersion: ROBOT_FIRMWARE_VERSION, + robotSerialNumber: ROBOT_SERIAL_NUMBER, }) }) }) diff --git a/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx index de223800946..bf9969b5a7b 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx @@ -72,7 +72,7 @@ describe('useTrackCreateProtocolRunEvent hook', () => { it('returns trackCreateProtocolRunEvent function', () => { const { result } = renderHook( - () => useTrackCreateProtocolRunEvent(storedProtocolData), + () => useTrackCreateProtocolRunEvent(storedProtocolData, 'otie'), { wrapper, } @@ -82,7 +82,7 @@ describe('useTrackCreateProtocolRunEvent hook', () => { it('trackCreateProtocolRunEvent invokes trackEvent with correct props', async () => { const { result } = renderHook( - () => useTrackCreateProtocolRunEvent(storedProtocolData), + () => useTrackCreateProtocolRunEvent(storedProtocolData, 'otie'), { wrapper, } @@ -107,7 +107,7 @@ describe('useTrackCreateProtocolRunEvent hook', () => { }) ) const { result } = renderHook( - () => useTrackCreateProtocolRunEvent(storedProtocolData), + () => useTrackCreateProtocolRunEvent(storedProtocolData, 'otie'), { wrapper, } diff --git a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx index 5dfff1c91b4..3adff13e65c 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx @@ -27,6 +27,7 @@ const mockUseProtocolRunAnalyticsData = useProtocolRunAnalyticsData as jest.Mock > const RUN_ID = 'runId' +const ROBOT_NAME = 'otie' const PROTOCOL_PROPERTIES = { protocolType: 'python' } let mockTrackEvent: jest.Mock @@ -54,9 +55,11 @@ describe('useTrackProtocolRunEvent hook', () => { ) ) mockUseTrackEvent.mockReturnValue(mockTrackEvent) - when(mockUseProtocolRunAnalyticsData).calledWith(RUN_ID).mockReturnValue({ - getProtocolRunAnalyticsData: mockGetProtocolRunAnalyticsData, - }) + when(mockUseProtocolRunAnalyticsData) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + getProtocolRunAnalyticsData: mockGetProtocolRunAnalyticsData, + }) }) afterEach(() => { @@ -65,16 +68,22 @@ describe('useTrackProtocolRunEvent hook', () => { }) it('returns trackProtocolRunEvent function', () => { - const { result } = renderHook(() => useTrackProtocolRunEvent(RUN_ID), { - wrapper, - }) + const { result } = renderHook( + () => useTrackProtocolRunEvent(RUN_ID, ROBOT_NAME), + { + wrapper, + } + ) expect(typeof result.current.trackProtocolRunEvent).toBe('function') }) it('trackProtocolRunEvent invokes trackEvent with correct props', async () => { - const { result } = renderHook(() => useTrackProtocolRunEvent(RUN_ID), { - wrapper, - }) + const { result } = renderHook( + () => useTrackProtocolRunEvent(RUN_ID, ROBOT_NAME), + { + wrapper, + } + ) await waitFor(() => result.current.trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_START, @@ -89,16 +98,19 @@ describe('useTrackProtocolRunEvent hook', () => { it('trackProtocolRunEvent calls trackEvent without props when error is thrown in getProtocolRunAnalyticsData', async () => { when(mockUseProtocolRunAnalyticsData) - .calledWith('errorId') + .calledWith('errorId', ROBOT_NAME) .mockReturnValue({ getProtocolRunAnalyticsData: () => new Promise(() => { throw new Error('error') }), }) - const { result } = renderHook(() => useTrackProtocolRunEvent('errorId'), { - wrapper, - }) + const { result } = renderHook( + () => useTrackProtocolRunEvent('errorId', ROBOT_NAME), + { + wrapper, + } + ) await waitFor(() => result.current.trackProtocolRunEvent({ name: ANALYTICS_PROTOCOL_RUN_START, diff --git a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts b/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts index 653e352384c..a6b83a93088 100644 --- a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts +++ b/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts @@ -2,7 +2,12 @@ import { useSelector } from 'react-redux' import { hash } from '../../../redux/analytics/hash' import { getStoredProtocol } from '../../../redux/protocol-storage' -import { useStoredProtocolAnalysis, useProtocolDetailsForRun } from './' +import { getRobotSerialNumber } from '../../../redux/discovery' +import { + useRobot, + useStoredProtocolAnalysis, + useProtocolDetailsForRun, +} from './' import { useProtocolMetadata } from './useProtocolMetadata' import { useRunTimestamps } from '../../RunTimeControl/hooks' import { formatInterval } from '../../RunTimeControl/utils' @@ -16,13 +21,18 @@ import type { State } from '../../../redux/types' export const parseProtocolRunAnalyticsData = ( protocolAnalysis: ProtocolAnalysisOutput | null, storedProtocol: StoredProtocolData | null, - startedAt: string | null + startedAt: string | null, + robotName: string ) => () => { const hashTasks = [ hash(protocolAnalysis?.metadata?.author) ?? '', hash(storedProtocol?.srcFiles?.toString() ?? '') ?? '', ] + const robot = useRobot(robotName) + const serialNumber = + robot?.status != null ? getRobotSerialNumber(robot) : null + return Promise.all(hashTasks).then(([protocolAuthor, protocolText]) => ({ protocolRunAnalyticsData: { protocolType: protocolAnalysis?.config?.protocolType ?? '', @@ -49,6 +59,7 @@ export const parseProtocolRunAnalyticsData = ( protocolAnalysis?.robotType != null ? protocolAnalysis?.robotType : storedProtocol?.mostRecentAnalysis?.robotType, + robotSerialNumber: serialNumber ?? '', }, runTime: startedAt != null ? formatInterval(startedAt, Date()) : EMPTY_TIMESTAMP, @@ -68,7 +79,8 @@ type GetProtocolRunAnalyticsData = () => Promise<{ * data properties for use in event trackEvent */ export function useProtocolRunAnalyticsData( - runId: string | null + runId: string | null, + robotName: string ): { getProtocolRunAnalyticsData: GetProtocolRunAnalyticsData } { @@ -96,7 +108,8 @@ export function useProtocolRunAnalyticsData( const getProtocolRunAnalyticsData = parseProtocolRunAnalyticsData( protocolAnalysis as ProtocolAnalysisOutput | null, storedProtocol, - startedAt + startedAt, + robotName ) return { getProtocolRunAnalyticsData } diff --git a/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts b/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts index 6ca8c95fbca..94037f05b2a 100644 --- a/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts +++ b/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts @@ -7,6 +7,7 @@ import { getRobotSettings, fetchSettings } from '../../../redux/robot-settings' import { getRobotApiVersion, getRobotFirmwareVersion, + getRobotSerialNumber, } from '../../../redux/discovery' import type { State, Dispatch } from '../../../redux/types' @@ -30,6 +31,8 @@ export function useRobotAnalyticsData( const settings = useSelector((state: State) => getRobotSettings(state, robotName) ) + const serialNumber = + robot?.status != null ? getRobotSerialNumber(robot) : null const dispatch = useDispatch() React.useEffect(() => { @@ -50,6 +53,7 @@ export function useRobotAnalyticsData( robotSmoothieVersion: getRobotFirmwareVersion(robot) ?? '', robotLeftPipette: pipettes.left?.model ?? '', robotRightPipette: pipettes.right?.model ?? '', + robotSerialNumber: serialNumber ?? '', } ) } diff --git a/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts b/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts index f698b08e0f2..400f93fac40 100644 --- a/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts +++ b/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts @@ -18,7 +18,8 @@ type TrackCreateProtocolRunEvent = ( ) => void export function useTrackCreateProtocolRunEvent( - protocol: StoredProtocolData | null + protocol: StoredProtocolData | null, + robotName: string ): { trackCreateProtocolRunEvent: TrackCreateProtocolRunEvent } { const trackEvent = useTrackEvent() @@ -29,7 +30,8 @@ export function useTrackCreateProtocolRunEvent( const getProtocolRunAnalyticsData = parseProtocolRunAnalyticsData( storedProtocolAnalysis, protocol, - null + null, + robotName ) const trackCreateProtocolRunEvent: TrackCreateProtocolRunEvent = ({ diff --git a/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts b/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts index 89dc55a0f23..7cc354805b2 100644 --- a/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts +++ b/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts @@ -11,10 +11,14 @@ export type TrackProtocolRunEvent = ( ) => void export function useTrackProtocolRunEvent( - runId: string | null + runId: string | null, + robotName: string ): { trackProtocolRunEvent: TrackProtocolRunEvent } { const trackEvent = useTrackEvent() - const { getProtocolRunAnalyticsData } = useProtocolRunAnalyticsData(runId) + const { getProtocolRunAnalyticsData } = useProtocolRunAnalyticsData( + runId, + robotName + ) const trackProtocolRunEvent: TrackProtocolRunEvent = ({ name, diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx index 7b76e34aeb4..7c4aa964296 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx @@ -36,6 +36,7 @@ jest.mock('../../../../resources/runs/useNotifyAllRunsQuery') jest.mock('../../../../resources/health/hooks') const RUN_ID = 'mockRunId' +const ROBOT_NAME = 'otie' const mockMissingPipette = [ { @@ -144,9 +145,11 @@ describe('RecentRunProtocolCard', () => { mockUseProtocolQuery.mockReturnValue({ data: { data: { metadata: { protocolName: 'mockProtocol' } } }, } as any) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) mockCloneRun = jest.fn() when(mockUseCloneRun) .calledWith(RUN_ID, expect.anything()) diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx index 6f1c103df0f..21f48b59843 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useHistory } from 'react-router-dom' +import { useSelector } from 'react-redux' import { RUN_STATUS_STOPPED } from '@opentrons/api-client' import { @@ -21,6 +22,7 @@ import { Modal } from '../../../molecules/Modal' import { useTrackProtocolRunEvent } from '../../../organisms/Devices/hooks' import { useRunStatus } from '../../../organisms/RunTimeControl/hooks' import { ANALYTICS_PROTOCOL_RUN_CANCEL } from '../../../redux/analytics' +import { getLocalRobot } from '../../../redux/discovery' import { CancelingRunModal } from './CancelingRunModal' import type { ModalHeaderBaseProps } from '../../../molecules/Modal/types' @@ -45,7 +47,9 @@ export function ConfirmCancelRunModal({ isLoading: isDismissing, } = useDismissCurrentRunMutation() const runStatus = useRunStatus(runId) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const localRobot = useSelector(getLocalRobot) + const robotName = localRobot?.name ?? '' + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const history = useHistory() const [isCanceling, setIsCanceling] = React.useState(false) diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx index 3208e81fb63..bd802d535b8 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx @@ -14,6 +14,8 @@ import { i18n } from '../../../../i18n' import { useTrackProtocolRunEvent } from '../../../../organisms/Devices/hooks' import { useRunStatus } from '../../../../organisms/RunTimeControl/hooks' import { useTrackEvent } from '../../../../redux/analytics' +import { getLocalRobot } from '../../../../redux/discovery' +import { mockConnectedRobot } from '../../../../redux/discovery/__fixtures__' import { ConfirmCancelRunModal } from '../ConfirmCancelRunModal' import { CancelingRunModal } from '../CancelingRunModal' @@ -23,6 +25,7 @@ jest.mock('../../../../organisms/RunTimeControl/hooks') jest.mock('../../../../redux/analytics') jest.mock('../../../ProtocolUpload/hooks') jest.mock('../CancelingRunModal') +jest.mock('../../../../redux/discovery') const mockPush = jest.fn() let mockStopRun: jest.Mock @@ -56,6 +59,9 @@ const mockCancelingRunModal = CancelingRunModal as jest.MockedFunction< const mockUseRunStatus = useRunStatus as jest.MockedFunction< typeof useRunStatus > +const mockGetLocalRobot = getLocalRobot as jest.MockedFunction< + typeof getLocalRobot +> const render = (props: React.ComponentProps) => { return renderWithProviders( @@ -69,6 +75,7 @@ const render = (props: React.ComponentProps) => { } const RUN_ID = 'mock_runID' +const ROBOT_NAME = 'otie' const mockFn = jest.fn() describe('ConfirmCancelRunModal', () => { @@ -86,15 +93,21 @@ describe('ConfirmCancelRunModal', () => { mockTrackProtocolRunEvent = jest.fn( () => new Promise(resolve => resolve({})) ) + mockGetLocalRobot.mockReturnValue({ + ...mockConnectedRobot, + name: ROBOT_NAME, + }) mockUseStopRunMutation.mockReturnValue({ stopRun: mockStopRun } as any) mockUseDismissCurrentRunMutation.mockReturnValue({ dismissCurrentRun: mockDismissCurrentRun, isLoading: false, } as any) mockUseTrackEvent.mockReturnValue(mockTrackEvent) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) mockCancelingRunModal.mockReturnValue(
mock CancelingRunModal
) when(mockUseRunStatus).calledWith(RUN_ID).mockReturnValue(RUN_STATUS_IDLE) }) diff --git a/app/src/organisms/RunDetails/ConfirmCancelModal.tsx b/app/src/organisms/RunDetails/ConfirmCancelModal.tsx index 5bd04903937..d55d4900e4b 100644 --- a/app/src/organisms/RunDetails/ConfirmCancelModal.tsx +++ b/app/src/organisms/RunDetails/ConfirmCancelModal.tsx @@ -28,16 +28,17 @@ import { ANALYTICS_PROTOCOL_RUN_CANCEL } from '../../redux/analytics' export interface ConfirmCancelModalProps { onClose: () => unknown runId: string + robotName: string } export function ConfirmCancelModal( props: ConfirmCancelModalProps ): JSX.Element { - const { onClose, runId } = props + const { onClose, runId, robotName } = props const { stopRun } = useStopRunMutation() const [isCanceling, setIsCanceling] = React.useState(false) const runStatus = useRunStatus(runId) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const { t } = useTranslation('run_details') const cancelRun: React.MouseEventHandler = (e): void => { diff --git a/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx b/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx index ed73d19abe3..a64c8a88e28 100644 --- a/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx +++ b/app/src/organisms/RunDetails/__tests__/ConfirmCancelModal.test.tsx @@ -41,6 +41,7 @@ const render = (props: React.ComponentProps) => { } const RUN_ID = 'mockRunId' +const ROBOT_NAME = 'otie' let mockStopRun: jest.Mock let mockTrackEvent: jest.Mock let mockTrackProtocolRunEvent: jest.Mock @@ -56,11 +57,13 @@ describe('ConfirmCancelModal', () => { mockUseStopRunMutation.mockReturnValue({ stopRun: mockStopRun } as any) mockUseRunStatus.mockReturnValue(RUN_STATUS_RUNNING) mockUseTrackEvent.mockReturnValue(mockTrackEvent) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) - props = { onClose: jest.fn(), runId: RUN_ID } + props = { onClose: jest.fn(), runId: RUN_ID, robotName: ROBOT_NAME } }) afterEach(() => { diff --git a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx index 196fde2acad..ca6d6b275f0 100644 --- a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx +++ b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx @@ -345,7 +345,7 @@ describe('ProtocolSetup', () => { } as unknown) as any) when(mockUseDeckConfigurationCompatibility).mockReturnValue([]) when(mockUseTrackProtocolRunEvent) - .calledWith(RUN_ID) + .calledWith(RUN_ID, ROBOT_NAME) .mockReturnValue({ trackProtocolRunEvent: mockTrackProtocolRunEvent }) }) diff --git a/app/src/pages/ProtocolSetup/index.tsx b/app/src/pages/ProtocolSetup/index.tsx index 46011492e54..950eb60991e 100644 --- a/app/src/pages/ProtocolSetup/index.tsx +++ b/app/src/pages/ProtocolSetup/index.tsx @@ -343,7 +343,7 @@ function PrepareToRun({ mostRecentAnalysis ) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const robotAnalyticsData = useRobotAnalyticsData(robotName) const requiredDeckConfigCompatibility = getRequiredDeckConfig( diff --git a/app/src/pages/RunSummary/index.tsx b/app/src/pages/RunSummary/index.tsx index 521d1fd0480..272544af63f 100644 --- a/app/src/pages/RunSummary/index.tsx +++ b/app/src/pages/RunSummary/index.tsx @@ -107,12 +107,12 @@ export function RunSummary(): JSX.Element { const [showSplash, setShowSplash] = React.useState( runStatus === RUN_STATUS_FAILED || runStatus === RUN_STATUS_SUCCEEDED ) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) + const localRobot = useSelector(getLocalRobot) + const robotName = localRobot?.name ?? 'no name' + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const { reset } = useRunControls(runId) const trackEvent = useTrackEvent() const { closeCurrentRun, isClosingCurrentRun } = useCloseCurrentRun() - const localRobot = useSelector(getLocalRobot) - const robotName = localRobot?.name ?? 'no name' const robotAnalyticsData = useRobotAnalyticsData(robotName) const [showRunFailedModal, setShowRunFailedModal] = React.useState( false diff --git a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx index 83f4576fd6a..0656e2180f0 100644 --- a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx +++ b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx @@ -17,6 +17,7 @@ import { useRunActionMutations, } from '@opentrons/react-api-client' +import { getLocalRobot } from '../../../redux/discovery' import { mockRobotSideAnalysis } from '../../../organisms/CommandText/__fixtures__' import { CurrentRunningProtocolCommand, @@ -24,6 +25,7 @@ import { RunningProtocolSkeleton, } from '../../../organisms/OnDeviceDisplay/RunningProtocol' import { mockUseAllCommandsResponseNonDeterministic } from '../../../organisms/RunProgressMeter/__fixtures__' +import { mockConnectedRobot } from '../../../redux/discovery/__fixtures__' import { useRunStatus, useRunTimestamps, @@ -100,8 +102,12 @@ const mockOpenDoorAlertModal = OpenDoorAlertModal as jest.MockedFunction< const mockUseNotifyLastRunCommandKey = useNotifyLastRunCommandKey as jest.MockedFunction< typeof useNotifyLastRunCommandKey > +const mockGetLocalRobot = getLocalRobot as jest.MockedFunction< + typeof getLocalRobot +> const RUN_ID = 'run_id' +const ROBOT_NAME = 'otie' const PROTOCOL_ID = 'protocol_id' const PROTOCOL_KEY = 'protocol_key' const PROTOCOL_ANALYSIS = { @@ -160,6 +166,10 @@ describe('RunningProtocol', () => { stoppedAt: '', completedAt: '2022-05-04T18:24:41.833862+00:00', }) + mockGetLocalRobot.mockReturnValue({ + ...mockConnectedRobot, + name: ROBOT_NAME, + }) when(mockUseRunActionMutations).calledWith(RUN_ID).mockReturnValue({ playRun: mockPlayRun, pauseRun: mockPauseRun, @@ -168,9 +178,11 @@ describe('RunningProtocol', () => { isPauseRunActionLoading: false, isStopRunActionLoading: false, }) - when(mockUseTrackProtocolRunEvent).calledWith(RUN_ID).mockReturnValue({ - trackProtocolRunEvent: mockTrackProtocolRunEvent, - }) + when(mockUseTrackProtocolRunEvent) + .calledWith(RUN_ID, ROBOT_NAME) + .mockReturnValue({ + trackProtocolRunEvent: mockTrackProtocolRunEvent, + }) when(mockUseMostRecentCompletedAnalysis) .calledWith(RUN_ID) .mockReturnValue(mockRobotSideAnalysis) diff --git a/app/src/pages/RunningProtocol/index.tsx b/app/src/pages/RunningProtocol/index.tsx index 4160cdd2ccc..a702b7bf881 100644 --- a/app/src/pages/RunningProtocol/index.tsx +++ b/app/src/pages/RunningProtocol/index.tsx @@ -110,9 +110,9 @@ export function RunningProtocol(): JSX.Element { protocolRecord?.data.metadata.protocolName ?? protocolRecord?.data.files[0].name const { playRun, pauseRun } = useRunActionMutations(runId) - const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId) const localRobot = useSelector(getLocalRobot) const robotName = localRobot != null ? localRobot.name : 'no name' + const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) const robotAnalyticsData = useRobotAnalyticsData(robotName) const robotType = useRobotType(robotName) React.useEffect(() => { diff --git a/app/src/redux/analytics/types.ts b/app/src/redux/analytics/types.ts index d5b96a2dd8c..ceb24166d0e 100644 --- a/app/src/redux/analytics/types.ts +++ b/app/src/redux/analytics/types.ts @@ -21,6 +21,7 @@ export interface ProtocolAnalyticsData { protocolText: string pipettes: string modules: string + robotSerialNumber: string } export type RobotAnalyticsData = { @@ -28,6 +29,7 @@ export type RobotAnalyticsData = { robotSmoothieVersion: string robotLeftPipette: string robotRightPipette: string + robotSerialNumber: string } & { // feature flags // e.g. robotFF_settingName