Skip to content

Commit

Permalink
fix(app): Handle combo of HS+setup step modals (#15942)
Browse files Browse the repository at this point in the history
If both need to be shown, both need to be shown. The setup steps modal
comes first and then the heater shaker modal.

## review/dev-testing
- [x] on ODD, when a heater/shaker is in the protocol, the confirm steps
modal comes first and then the confirm HS. clicking confirm HS is the
one that starts the run
- [x] on ODD, when there's no heater/shaker, the confirm steps modal
still pops and it starts the run when you click confirm
- [x] on Desktop, when there's a heater shaker in the protocol and you
haven't disabled the popup, the confirm steps modal comes first and then
confirm HS. clicking confirm HS is the one that starts the run
- [x] on Desktop, when there's a heater shaker in the protocol and you
have disabled the popup, the confirm steps modal is the only one and
clicking confirm starts the run
- [x] on Desktop, when there's no heater shaker in the protocol, the
confirm steps modal is the only one and clicking confirm starts the run


Closes RQA-2932
  • Loading branch information
sfoster1 authored Aug 9, 2024
1 parent 9f758bc commit c6c151d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 11 deletions.
17 changes: 11 additions & 6 deletions app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,11 @@ function ActionButton(props: ActionButtonProps): JSX.Element {
disableReason = t('close_door')
}

const shouldShowHSConfirm =
isHeaterShakerInProtocol &&
!isHeaterShakerShaking &&
(runStatus === RUN_STATUS_IDLE || runStatus === RUN_STATUS_STOPPED)

if (isProtocolAnalyzing) {
buttonIconName = 'ot-spinner'
buttonText = t('analyzing_on_robot')
Expand Down Expand Up @@ -777,11 +782,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element {
(runStatus === RUN_STATUS_IDLE || runStatus === RUN_STATUS_STOPPED)
) {
confirmMissingSteps()
} else if (
isHeaterShakerInProtocol &&
!isHeaterShakerShaking &&
(runStatus === RUN_STATUS_IDLE || runStatus === RUN_STATUS_STOPPED)
) {
} else if (shouldShowHSConfirm) {
confirmAttachment()
} else {
play()
Expand Down Expand Up @@ -867,7 +868,11 @@ function ActionButton(props: ActionButtonProps): JSX.Element {
{showMissingStepsConfirmationModal && (
<ConfirmMissingStepsModal
onCloseClick={cancelExitMissingStepsConfirmation}
onConfirmClick={handleProceedToRunClick}
onConfirmClick={() => {
shouldShowHSConfirm
? confirmAttachment()
: handleProceedToRunClick()
}}
missingSteps={missingSetupSteps}
/>
)}
Expand Down
50 changes: 50 additions & 0 deletions app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,58 @@ describe('ProtocolSetup', () => {

it('should render a confirmation modal when heater-shaker is in a protocol and it is not shaking', () => {
vi.mocked(useIsHeaterShakerInProtocol).mockReturnValue(true)
vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({
data: { ...mockRobotSideAnalysis, liquids: mockLiquids },
} as any)
when(vi.mocked(getProtocolModulesInfo))
.calledWith(
{ ...mockRobotSideAnalysis, liquids: mockLiquids },
flexDeckDefV5 as any
)
.thenReturn(mockProtocolModuleInfo)
when(vi.mocked(getUnmatchedModulesForProtocol))
.calledWith([], mockProtocolModuleInfo)
.thenReturn({ missingModuleIds: [], remainingAttachedModules: [] })
vi.mocked(getIncompleteInstrumentCount).mockReturnValue(0)
MockProtocolSetupLiquids.mockImplementation(
vi.fn(({ setIsConfirmed, setSetupScreen }) => {
setIsConfirmed(true)
setSetupScreen('prepare to run')
return <div>Mock ProtocolSetupLiquids</div>
})
)
MockProtocolSetupLabware.mockImplementation(
vi.fn(({ setIsConfirmed, setSetupScreen }) => {
setIsConfirmed(true)
setSetupScreen('prepare to run')
return <div>Mock ProtocolSetupLabware</div>
})
)
MockProtocolSetupOffsets.mockImplementation(
vi.fn(({ setIsConfirmed, setSetupScreen }) => {
setIsConfirmed(true)
setSetupScreen('prepare to run')
return <div>Mock ProtocolSetupOffsets</div>
})
)
render(`/runs/${RUN_ID}/setup/`)
fireEvent.click(screen.getByText('Labware Position Check'))
fireEvent.click(screen.getByText('Labware'))
fireEvent.click(screen.getByText('Liquids'))
fireEvent.click(screen.getByRole('button', { name: 'play' }))
expect(vi.mocked(ConfirmAttachedModal)).toHaveBeenCalled()
})
it('should go from skip steps to heater-shaker modal', () => {
vi.mocked(useIsHeaterShakerInProtocol).mockReturnValue(true)
MockConfirmSetupStepsCompleteModal.mockImplementation(
({ onConfirmClick }) => {
onConfirmClick()
return <div>Mock ConfirmSetupStepsCompleteModal</div>
}
)
render(`/runs/${RUN_ID}/setup/`)
fireEvent.click(screen.getByRole('button', { name: 'play' }))
expect(MockConfirmSetupStepsCompleteModal).toHaveBeenCalled()
expect(vi.mocked(ConfirmAttachedModal)).toHaveBeenCalled()
})
it('should render a loading skeleton while awaiting a response from the server', () => {
Expand Down
15 changes: 10 additions & 5 deletions app/src/pages/ProtocolSetup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,13 @@ function PrepareToRun({
makeSnackbar(t('shared:close_robot_door') as string)
} else {
if (isReadyToRun) {
if (runStatus === RUN_STATUS_IDLE && isHeaterShakerInProtocol) {
confirmAttachment()
} else if (
if (
runStatus === RUN_STATUS_IDLE &&
!(labwareConfirmed && offsetsConfirmed && liquidsConfirmed)
) {
confirmStepsComplete()
} else if (runStatus === RUN_STATUS_IDLE && isHeaterShakerInProtocol) {
confirmAttachment()
} else {
play()
trackProtocolRunEvent({
Expand Down Expand Up @@ -957,6 +957,8 @@ export function ProtocolSetup(): JSX.Element {
handleProceedToRunClick,
!(labwareConfirmed && liquidsConfirmed && offsetsConfirmed)
)
const runStatus = useRunStatus(runId)
const isHeaterShakerInProtocol = useIsHeaterShakerInProtocol()

// orchestrate setup subpages/components
const [setupScreen, setSetupScreen] = React.useState<SetupScreens>(
Expand Down Expand Up @@ -1027,7 +1029,6 @@ export function ProtocolSetup(): JSX.Element {
<ViewOnlyParameters runId={runId} setSetupScreen={setSetupScreen} />
),
}

return (
<>
{showAnalysisFailedModal &&
Expand All @@ -1043,7 +1044,11 @@ export function ProtocolSetup(): JSX.Element {
<ConfirmSetupStepsCompleteModal
onCloseClick={cancelExitMissingStepsConfirmation}
missingSteps={missingSteps}
onConfirmClick={handleProceedToRunClick}
onConfirmClick={() => {
runStatus === RUN_STATUS_IDLE && isHeaterShakerInProtocol
? confirmAttachment()
: handleProceedToRunClick()
}}
/>
) : null}
{showHSConfirmationModal ? (
Expand Down

0 comments on commit c6c151d

Please sign in to comment.