diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx index df77e460792..21d293c7d5f 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx @@ -3,6 +3,7 @@ import { css } from 'styled-components' import { useTranslation } from 'react-i18next' import { useHistory } from 'react-router-dom' import { formatDistance } from 'date-fns' +import last from 'lodash/last' import { BORDERS, @@ -17,14 +18,14 @@ import { StyledText, TYPOGRAPHY, } from '@opentrons/components' -import { useProtocolQuery } from '@opentrons/react-api-client' +import { + useProtocolAnalysisAsDocumentQuery, + useProtocolQuery, +} from '@opentrons/react-api-client' import { RUN_STATUS_FAILED, RUN_STATUS_STOPPED, RUN_STATUS_SUCCEEDED, - Run, - RunData, - RunStatus, } from '@opentrons/api-client' import { ODD_FOCUS_VISIBLE } from '../../../atoms/buttons//constants' @@ -38,6 +39,7 @@ import { INIT_STATUS, } from '../../../resources/health/hooks' +import type { Run, RunData, RunStatus } from '@opentrons/api-client' import type { ProtocolResource } from '@opentrons/shared-data' interface RecentRunProtocolCardProps { @@ -98,6 +100,14 @@ export function ProtocolWithLastRun({ const protocolName = protocolData.metadata.protocolName ?? protocolData.files[0].name + const protocolId = protocolData.id + + const { data: analysis } = useProtocolAnalysisAsDocumentQuery( + protocolId, + last(protocolData?.analysisSummaries)?.id ?? null, + { enabled: protocolData != null } + ) + const PROTOCOL_CARD_STYLE = css` flex: 1 0 0; &:active { @@ -125,13 +135,22 @@ export function ProtocolWithLastRun({ height: max-content; ` + const hasRunTimeParameters = + analysis?.runTimeParameters != null + ? analysis?.runTimeParameters.length > 0 + : false + const handleCardClick = (): void => { setShowSpinner(true) - cloneRun() - trackEvent({ - name: 'proceedToRun', - properties: { sourceLocation: 'RecentRunProtocolCard' }, - }) + if (hasRunTimeParameters) { + history.push(`/protocols/${protocolId}`) + } else { + cloneRun() + trackEvent({ + name: 'proceedToRun', + properties: { sourceLocation: 'RecentRunProtocolCard' }, + }) + } // TODO(BC, 08/29/23): reintroduce this analytics event when we refactor the hook to fetch data lazily (performance concern) // trackProtocolRunEvent({ name: 'runAgain' }) } diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx index 1584e3ce723..10de409948a 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx @@ -5,8 +5,14 @@ import { MemoryRouter } from 'react-router-dom' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { when } from 'vitest-when' -import { useProtocolQuery } from '@opentrons/react-api-client' -import { RUN_STATUS_FAILED } from '@opentrons/api-client' +import { + useProtocolQuery, + useProtocolAnalysisAsDocumentQuery, +} from '@opentrons/react-api-client' +import { + RUN_STATUS_FAILED, + simpleAnalysisFileFixture, +} from '@opentrons/api-client' import { COLORS } from '@opentrons/components' import { renderWithProviders } from '../../../../__testing-utils__' @@ -24,11 +30,23 @@ import { INIT_STATUS, } from '../../../../resources/health/hooks' +import type { useHistory } from 'react-router-dom' import type { ProtocolHardware } from '../../../../pages/Protocols/hooks' +const mockPush = vi.fn() + +vi.mock('react-router-dom', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + useHistory: () => ({ push: mockPush } as any), + } +}) + vi.mock('@opentrons/react-api-client') vi.mock('../../../../atoms/Skeleton') vi.mock('../../../../pages/Protocols/hooks') +vi.mock('../../../../pages/ProtocolDetails') vi.mock('../../../../organisms/Devices/hooks') vi.mock('../../../../organisms/RunTimeControl/hooks') vi.mock('../../../../organisms/ProtocolUpload/hooks') @@ -128,7 +146,18 @@ describe('RecentRunProtocolCard', () => { data: { data: [mockRunData] }, } as any) vi.mocked(useProtocolQuery).mockReturnValue({ - data: { data: { metadata: { protocolName: 'mockProtocol' } } }, + data: { + data: { + metadata: { protocolName: 'mockProtocol' }, + id: 'mockProtocolId', + }, + }, + } as any) + vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({ + data: { + ...simpleAnalysisFileFixture, + runTimeParameters: [], + }, } as any) vi.mocked(useRobotInitializationStatus).mockReturnValue( INIT_STATUS.SUCCEEDED @@ -252,4 +281,14 @@ describe('RecentRunProtocolCard', () => { const [{ getByText }] = render(props) getByText('mock Skeleton') }) + + it('should push to protocol details if protocol contains runtime parameters', () => { + vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({ + data: simpleAnalysisFileFixture, + } as any) + render(props) + const button = screen.getByLabelText('RecentRunProtocolCard') + fireEvent.click(button) + expect(mockPush).toBeCalledWith('/protocols/mockProtocolId') + }) })