Skip to content

Commit

Permalink
fix(app): fix command sequencing for 96-Channel flows (#13681)
Browse files Browse the repository at this point in the history
  • Loading branch information
smb2268 authored Oct 10, 2023
1 parent 4e73c9b commit 981b3cb
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 56 deletions.
1 change: 1 addition & 0 deletions app/src/assets/localization/en/devices_landing.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"lights_on": "lights on",
"loading": "loading",
"looking_for_robots": "Looking for robots",
"ninety_six_mount": "Left + Right Mount",
"make_sure_robot_is_connected": "Make sure the robot is connected to this computer",
"modules": "Modules",
"no_robots_found": "No robots found",
Expand Down
1 change: 1 addition & 0 deletions app/src/assets/localization/en/pipette_wizard_flows.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"detach_and_retry": "detach and retry",
"detach_mount_attach_96": "Detach {{mount}} Pipette and Attach 96-Channel Pipette",
"detach_mounting_plate_instructions": "Hold onto the plate so it does not fall. Then remove the pins on the plate from the slots on the gantry carriage.",
"detach_next_pipette": "Detach next pipette",
"detach_pipette_to_attach_96": "Detach {{pipetteName}} and attach 96-Channel pipette",
"detach_pipette": "detach {{mount}} pipette",
"detach_pipettes_attach_96": "Detach Pipettes and Attach 96-Channel Pipette",
Expand Down
3 changes: 2 additions & 1 deletion app/src/organisms/ChangePipette/ConfirmPipette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export function ConfirmPipette(props: ConfirmPipetteProps): JSX.Element {
return !confirmPipetteLevel &&
(wrongWantedPipette != null || (props.wantedPipette != null && success)) &&
actualPipette != null &&
actualPipette.channels === 8 ? (
actualPipette.channels === 8 &&
actualPipette.displayCategory === 'GEN2' ? (
<LevelPipette
mount={mount}
pipetteModelName={actualPipette.name}
Expand Down
14 changes: 2 additions & 12 deletions app/src/organisms/Devices/PipetteCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,8 @@ import { useIsOT3 } from '../hooks'
import { PipetteOverflowMenu } from './PipetteOverflowMenu'
import { PipetteSettingsSlideout } from './PipetteSettingsSlideout'
import { AboutPipetteSlideout } from './AboutPipetteSlideout'

import type { State } from '../../../redux/types'
import type {
PipetteModelSpecs,
PipetteMount,
PipetteName,
} from '@opentrons/shared-data'
import type { PipetteModelSpecs, PipetteName } from '@opentrons/shared-data'
import type { AttachedPipette, Mount } from '../../../redux/pipettes/types'
import type {
PipetteWizardFlow,
Expand Down Expand Up @@ -175,12 +170,7 @@ export const PipetteCard = (props: PipetteCardProps): JSX.Element => {
{pipetteWizardFlow != null ? (
<PipetteWizardFlows
flowType={pipetteWizardFlow}
mount={
// hardcoding in LEFT mount for whenever a 96 channel is selected
selectedPipette === NINETY_SIX_CHANNEL
? LEFT
: (mount as PipetteMount)
}
mount={mount}
closeFlow={() => {
setSelectedPipette(SINGLE_MOUNT_PIPETTES)
setPipetteWizardFlow(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ export function SetupFlexPipetteCalibrationItem({
button={button}
calibratedDate={pipetteCalDate}
subText={subText}
label={t(`devices_landing:${mount}_mount`)}
label={
requestedPipetteSpecs?.channels === 96
? t('devices_landing:ninety_six_mount')
: t(`devices_landing:${mount}_mount`)
}
title={requestedPipetteSpecs?.displayName}
id={`PipetteCalibration_${mount}MountTitle`}
runId={runId}
Expand Down
73 changes: 68 additions & 5 deletions app/src/organisms/PipetteWizardFlows/Carriage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,73 @@
import * as React from 'react'
import { Trans, useTranslation } from 'react-i18next'
import capitalize from 'lodash/capitalize'
import { SPACING, PrimaryButton } from '@opentrons/components'
import {
TYPOGRAPHY,
COLORS,
SPACING,
PrimaryButton,
} from '@opentrons/components'
import { StyledText } from '../../atoms/text'
import { SmallButton } from '../../atoms/buttons'
import { GenericWizardTile } from '../../molecules/GenericWizardTile'
import { SimpleWizardBody } from '../../molecules/SimpleWizardBody'
import { getPipetteAnimations96 } from './utils'
import { BODY_STYLE, FLOWS, SECTIONS } from './constants'

import type { PipetteWizardStepProps } from './types'

export const Carriage = (props: PipetteWizardStepProps): JSX.Element | null => {
const { goBack, flowType, isOnDevice, proceed } = props
const {
goBack,
flowType,
isOnDevice,
proceed,
chainRunCommands,
errorMessage,
setShowErrorMessage,
} = props
const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared'])

return (
const handleReattachCarriageProceed = (): void => {
chainRunCommands?.(
[
{
commandType: 'home' as const,
params: {
axes: ['rightZ'],
},
},
],
false
)
.then(() => {
proceed()
})
.catch(error => {
setShowErrorMessage(error.message)
})
}

return errorMessage != null ? (
<SimpleWizardBody
isSuccess={false}
iconColor={COLORS.errorEnabled}
header={t('shared:error_encountered')}
subHeader={
<Trans
t={t}
i18nKey={'detach_pipette_error'}
values={{ error: errorMessage }}
components={{
block: <StyledText as="p" />,
bold: (
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold} />
),
}}
/>
}
/>
) : (
<GenericWizardTile
header={i18n.format(
t(flowType === FLOWS.ATTACH ? 'unscrew_carriage' : 'reattach_carriage'),
Expand All @@ -41,11 +94,21 @@ export const Carriage = (props: PipetteWizardStepProps): JSX.Element | null => {
proceedButton={
isOnDevice ? (
<SmallButton
onClick={proceed}
onClick={
flowType === FLOWS.ATTACH
? proceed
: handleReattachCarriageProceed
}
buttonText={capitalize(t('shared:continue'))}
/>
) : (
<PrimaryButton onClick={proceed}>
<PrimaryButton
onClick={
flowType === FLOWS.ATTACH
? proceed
: handleReattachCarriageProceed
}
>
{capitalize(t('shared:continue'))}
</PrimaryButton>
)
Expand Down
37 changes: 33 additions & 4 deletions app/src/organisms/PipetteWizardFlows/DetachPipette.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import { RIGHT } from '@opentrons/shared-data'
import { TYPOGRAPHY, COLORS } from '@opentrons/components'
import { StyledText } from '../../atoms/text'
import { GenericWizardTile } from '../../molecules/GenericWizardTile'
import { SimpleWizardBody } from '../../molecules/SimpleWizardBody'
import { Skeleton } from '../../atoms/Skeleton'
import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal'
import { CheckPipetteButton } from './CheckPipetteButton'
Expand All @@ -28,6 +30,8 @@ export const DetachPipette = (props: DetachPipetteProps): JSX.Element => {
chainRunCommands,
isOnDevice,
flowType,
errorMessage,
setShowErrorMessage,
} = props
const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared'])
const pipetteWizardStep = {
Expand All @@ -41,6 +45,12 @@ export const DetachPipette = (props: DetachPipetteProps): JSX.Element => {
const handle96ChannelProceed = (): void => {
chainRunCommands?.(
[
{
commandType: 'home' as const,
params: {
axes: ['leftZ'],
},
},
{
commandType: 'calibration/moveToMaintenancePosition' as const,
params: {
Expand All @@ -54,8 +64,8 @@ export const DetachPipette = (props: DetachPipetteProps): JSX.Element => {
.then(() => {
proceed()
})
.catch(() => {
proceed()
.catch(error => {
setShowErrorMessage(error.message)
})
}
const channel = memoizedAttachedPipettes[mount]?.data.channels
Expand All @@ -80,7 +90,26 @@ export const DetachPipette = (props: DetachPipetteProps): JSX.Element => {
}

if (isRobotMoving) return <InProgressModal description={t('stand_back')} />
return (
return errorMessage != null ? (
<SimpleWizardBody
isSuccess={false}
iconColor={COLORS.errorEnabled}
header={t('shared:error_encountered')}
subHeader={
<Trans
t={t}
i18nKey={'detach_pipette_error'}
values={{ error: errorMessage }}
components={{
block: <StyledText as="p" />,
bold: (
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold} />
),
}}
/>
}
/>
) : (
<GenericWizardTile
header={
isFetching ? (
Expand Down
38 changes: 37 additions & 1 deletion app/src/organisms/PipetteWizardFlows/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import {
getPipetteNameSpecs,
LEFT,
RIGHT,
LoadedPipette,
MotorAxes,
NINETY_SIX_CHANNEL,
Expand All @@ -34,6 +35,7 @@ interface ResultsProps extends PipetteWizardStepProps {
setFetching: React.Dispatch<React.SetStateAction<boolean>>
hasCalData: boolean
requiredPipette?: LoadedPipette
nextMount?: string
}

export const Results = (props: ResultsProps): JSX.Element => {
Expand All @@ -55,6 +57,7 @@ export const Results = (props: ResultsProps): JSX.Element => {
isRobotMoving,
requiredPipette,
setShowErrorMessage,
nextMount,
} = props
const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared'])
const pipetteName =
Expand Down Expand Up @@ -120,10 +123,15 @@ export const Results = (props: ResultsProps): JSX.Element => {
header = t('ninety_six_detached_success', {
pipetteName: NINETY_SIX_CHANNEL,
})
} else {
} else if (
attachedPipettes[LEFT] == null &&
attachedPipettes[RIGHT] == null
) {
header = t('all_pipette_detached')
subHeader = t('gantry_empty_for_96_channel_success')
buttonText = t('attach_pip')
} else {
buttonText = t('detach_next_pip')
}
}
}
Expand All @@ -134,11 +142,39 @@ export const Results = (props: ResultsProps): JSX.Element => {
const handleProceed = (): void => {
if (currentStepIndex === totalStepCount || !isSuccess) {
handleCleanUpAndClose()
} else if (isSuccess && nextMount != null) {
// move the gantry into the correct position for the next step of strung together flows
chainRunCommands?.(
[
{
commandType: 'home' as const,
params: {
axes: ['leftZ', 'rightZ'],
},
},
{
commandType: 'calibration/moveToMaintenancePosition' as const,
params: {
mount: nextMount === 'right' ? RIGHT : 'left',
maintenancePosition:
nextMount === 'both' ? 'attachPlate' : 'attachInstrument',
},
},
],
false
)
.then(() => {
proceed()
})
.catch(error => {
setShowErrorMessage(error.message)
})
} else if (
isSuccess &&
flowType === FLOWS.ATTACH &&
currentStepIndex !== totalStepCount
) {
// proceeding to attach probe for calibration
const axes: MotorAxes =
mount === LEFT ? ['leftPlunger'] : ['rightPlunger']
chainRunCommands?.(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ describe('Results', () => {
it('renders the correct information when pipette cal is a success for calibrate flow', () => {
props = {
...props,
currentStepIndex: 6,
totalStepCount: 6,
hasCalData: true,
}
const { getByText, getByRole } = render(props)
Expand All @@ -71,7 +73,7 @@ describe('Results', () => {
getByText('Exit')
const exit = getByRole('button', { name: 'Results_exit' })
fireEvent.click(exit)
expect(props.proceed).toHaveBeenCalled()
expect(props.handleCleanUpAndClose).toHaveBeenCalled()
})

it('renders the correct information when pipette wizard is a success for attach flow', async () => {
Expand All @@ -84,9 +86,8 @@ describe('Results', () => {
const image = getByRole('img', { name: 'Success Icon' })
expect(image.getAttribute('src')).toEqual('icon_success.png')
getByRole('img', { name: 'Success Icon' })
getByText('Calibrate pipette')
const exit = getByRole('button', { name: 'Results_exit' })
fireEvent.click(exit)
getByRole('button', { name: 'Results_exit' })
fireEvent.click(getByText('Calibrate pipette'))
expect(props.chainRunCommands).toHaveBeenCalledWith(
[
{
Expand Down
Loading

0 comments on commit 981b3cb

Please sign in to comment.