Skip to content

Commit

Permalink
fix(app): replace pipette flow updates and cleanup (#12764)
Browse files Browse the repository at this point in the history
  • Loading branch information
smb2268 authored May 23, 2023
1 parent ddd0fc6 commit 4c68ff5
Show file tree
Hide file tree
Showing 16 changed files with 378 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function SetupInstrumentCalibration({
const { t } = useTranslation('protocol_setup')
const runPipetteInfoByMount = useRunPipetteInfoByMount(runId)

const { data: instrumentsQueryData } = useInstrumentsQuery()
const { data: instrumentsQueryData, refetch } = useInstrumentsQuery()
const mostRecentAnalysis = useMostRecentCompletedAnalysis(runId)
const storedProtocolAnalysis = useStoredProtocolAnalysis(runId)
const usesGripper = isGripperInCommands(
Expand Down Expand Up @@ -62,6 +62,7 @@ export function SetupInstrumentCalibration({
mount={mount}
robotName={robotName}
runId={runId}
instrumentsRefetch={refetch}
/>
) : null
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ interface SetupInstrumentCalibrationItemProps {
mount: Mount
robotName: string
runId: string
instrumentsRefetch?: () => void
}

export function SetupPipetteCalibrationItem({
pipetteInfo,
mount,
robotName,
runId,
instrumentsRefetch,
}: SetupInstrumentCalibrationItemProps): JSX.Element | null {
const { t } = useTranslation(['protocol_setup', 'devices_landing'])
const deviceDetailsUrl = `/devices/${robotName}`
Expand Down Expand Up @@ -194,6 +196,7 @@ export function SetupPipetteCalibrationItem({
: SINGLE_MOUNT_PIPETTES
}
pipetteInfo={mostRecentAnalysis?.pipettes}
onComplete={instrumentsRefetch}
/>
)}
<SetupCalibrationItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ interface ProtocolInstrumentMountItemProps {
| GripperData['data']['calibratedOffset']
| null
speccedName: PipetteName | GripperModel
instrumentsRefetch?: () => void
}
export function ProtocolInstrumentMountItem(
props: ProtocolInstrumentMountItemProps
Expand Down Expand Up @@ -155,6 +156,7 @@ export function ProtocolInstrumentMountItem(
selectedPipette={selectedPipette}
mount={mount as Mount}
pipetteInfo={mostRecentAnalysis?.pipettes}
onComplete={props.instrumentsRefetch}
/>
) : null}
</>
Expand Down
1 change: 1 addition & 0 deletions app/src/organisms/PipetteWizardFlows/AttachProbe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => {
errorMessage={errorMessage}
chainRunCommands={chainRunCommands}
mount={mount}
setShowErrorMessage={setShowErrorMessage}
/>
) : (
<GenericWizardTile
Expand Down
47 changes: 43 additions & 4 deletions app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
RIGHT,
SINGLE_MOUNT_PIPETTES,
WEIGHT_OF_96_CHANNEL,
LoadedPipette,
getPipetteNameSpecs,
} from '@opentrons/shared-data'
import { Trans, useTranslation } from 'react-i18next'
import { StyledText } from '../../atoms/text'
Expand Down Expand Up @@ -40,6 +42,7 @@ interface BeforeBeginningProps extends PipetteWizardStepProps {
unknown
>
isCreateLoading: boolean
requiredPipette?: LoadedPipette
}
export const BeforeBeginning = (
props: BeforeBeginningProps
Expand All @@ -57,6 +60,7 @@ export const BeforeBeginning = (
setShowErrorMessage,
selectedPipette,
isOnDevice,
requiredPipette,
} = props
const { t } = useTranslation('pipette_wizard_flows')
React.useEffect(() => {
Expand Down Expand Up @@ -86,11 +90,24 @@ export const BeforeBeginning = (
}
case FLOWS.ATTACH: {
bodyTranslationKey = 'remove_labware'
let displayName: string | undefined
if (requiredPipette != null) {
displayName =
getPipetteNameSpecs(requiredPipette.pipetteName)?.displayName ??
requiredPipette.pipetteName
}
if (selectedPipette === SINGLE_MOUNT_PIPETTES) {
equipmentList = [PIPETTE, CALIBRATION_PROBE, HEX_SCREWDRIVER]
equipmentList = [
{ ...PIPETTE, displayName: displayName ?? PIPETTE.displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
]
} else {
equipmentList = [
NINETY_SIX_CHANNEL_PIPETTE,
{
...NINETY_SIX_CHANNEL_PIPETTE,
displayName: displayName ?? NINETY_SIX_CHANNEL_PIPETTE.displayName,
},
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
NINETY_SIX_CHANNEL_MOUNTING_PLATE,
Expand All @@ -99,8 +116,30 @@ export const BeforeBeginning = (
break
}
case FLOWS.DETACH: {
bodyTranslationKey = 'get_started_detach'
equipmentList = [HEX_SCREWDRIVER]
if (requiredPipette != null) {
const displayName =
getPipetteNameSpecs(requiredPipette.pipetteName)?.displayName ??
requiredPipette.pipetteName
bodyTranslationKey = 'remove_labware'

if (requiredPipette.pipetteName === 'p1000_96') {
equipmentList = [
{ ...NINETY_SIX_CHANNEL_PIPETTE, displayName: displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
NINETY_SIX_CHANNEL_MOUNTING_PLATE,
]
} else {
equipmentList = [
{ ...PIPETTE, displayName: displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
]
}
} else {
bodyTranslationKey = 'get_started_detach'
equipmentList = [HEX_SCREWDRIVER]
}
break
}
}
Expand Down
18 changes: 14 additions & 4 deletions app/src/organisms/PipetteWizardFlows/CalibrationErrorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ interface CalibrationErrorModalProps {
continuePastCommandFailure: boolean
) => Promise<any>
mount: PipetteMount
setShowErrorMessage: (message: string) => void
}

export function CalibrationErrorModal(
props: CalibrationErrorModalProps
): JSX.Element {
const { proceed, isOnDevice, errorMessage, chainRunCommands, mount } = props
const {
proceed,
isOnDevice,
errorMessage,
chainRunCommands,
mount,
setShowErrorMessage,
} = props
const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared'])
const handleProceed = (): void => {
chainRunCommands(
Expand All @@ -33,9 +41,11 @@ export function CalibrationErrorModal(
},
],
false
).then(() => {
proceed()
})
)
.then(() => {
proceed()
})
.catch(error => setShowErrorMessage(error.message))
}
return (
<SimpleWizardBody
Expand Down
48 changes: 44 additions & 4 deletions app/src/organisms/PipetteWizardFlows/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const Results = (props: ResultsProps): JSX.Element => {
hasCalData,
isRobotMoving,
requiredPipette,
setShowErrorMessage,
} = props
const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared'])
const pipetteName =
Expand Down Expand Up @@ -103,6 +104,9 @@ export const Results = (props: ResultsProps): JSX.Element => {
isSuccess = false
} else {
header = i18n.format(t('pipette_detached'), 'capitalize')
if (requiredPipette != null) {
buttonText = t('attach_pip')
}
if (selectedPipette === NINETY_SIX_CHANNEL) {
if (currentStepIndex === totalStepCount) {
header = t('ninety_six_detached_success', {
Expand Down Expand Up @@ -130,6 +134,15 @@ export const Results = (props: ResultsProps): JSX.Element => {
const axis = mount === 'left' ? 'leftPlunger' : 'rightPlunger'
chainRunCommands(
[
{
commandType: 'loadPipette' as const,
params: {
// @ts-expect-error pipetteName is required but missing in schema v6 type
pipetteName: attachedPipettes[mount]?.instrumentName,
pipetteId: attachedPipettes[mount]?.serialNumber,
mount: mount,
},
},
{
commandType: 'home' as const,
params: {
Expand All @@ -144,10 +157,37 @@ export const Results = (props: ResultsProps): JSX.Element => {
},
},
],
true
).then(() => {
proceed()
})
false
)
.then(() => {
proceed()
})
.catch(error => {
setShowErrorMessage(error.message)
})
} else if (
isSuccess &&
flowType === FLOWS.DETACH &&
currentStepIndex !== totalStepCount
) {
chainRunCommands(
[
{
// @ts-expect-error calibration type not yet supported
commandType: 'calibration/moveToMaintenancePosition' as const,
params: {
mount: mount,
},
},
],
false
)
.then(() => {
proceed()
})
.catch(error => {
setShowErrorMessage(error.message)
})
} else {
proceed()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('BeforeBeginning', () => {
isCreateLoading: false,
isRobotMoving: false,
isOnDevice: false,
requiredPipette: undefined,
}
// mockNeedHelpLink.mockReturnValue(<div>mock need help link</div>)
mockInProgressModal.mockReturnValue(<div>mock in progress</div>)
Expand Down Expand Up @@ -170,6 +171,56 @@ describe('BeforeBeginning', () => {
expect(props.proceed).toHaveBeenCalled()
})
})
it('renders the attach flow when swapping pipettes is needed', async () => {
props = {
...props,
attachedPipettes: { left: mockAttachedPipetteInformation, right: null },
flowType: FLOWS.DETACH,
requiredPipette: {
mount: LEFT,
id: 'abc',
pipetteName: 'p1000_single_gen3',
},
}
const { getByText, getByAltText, getByRole } = render(props)
getByText('Before you begin')
getByText(
'To get started, remove labware from the deck and clean up the working area to make attachment and calibration easier. Also gather the needed equipment shown to the right.'
)
getByText(
'The calibration probe is included with the robot and should be stored on the front pillar of the robot.'
)
getByAltText('Flex 1-Channel 1000 μL')
getByText('You will need:')
getByAltText('Calibration Probe')
getByAltText('2.5 mm Hex Screwdriver')
getByText(
'Provided with the robot. Using another size can strip the instruments’s screws.'
)
const proceedBtn = getByRole('button', { name: 'Move gantry to front' })
fireEvent.click(proceedBtn)
expect(props.chainRunCommands).toHaveBeenCalledWith(
[
{
commandType: 'loadPipette',
params: {
mount: LEFT,
pipetteId: 'abc',
pipetteName: 'p1000_single_gen3',
},
},
{ commandType: 'home' as const, params: {} },
{
commandType: 'calibration/moveToMaintenancePosition',
params: { mount: LEFT },
},
],
false
)
await waitFor(() => {
expect(props.proceed).toHaveBeenCalled()
})
})
})
describe('detach flow single mount', () => {
it('renders the modal with all correct text. clicking on proceed button sends commands for detach flow', async () => {
Expand Down Expand Up @@ -362,6 +413,63 @@ describe('BeforeBeginning', () => {
expect(props.proceed).toHaveBeenCalled()
})
})
it('renders the detach and attach 96 channel flow when there is a required 96-channel', async () => {
mockGetIsGantryEmpty.mockReturnValue(false)
props = {
...props,
attachedPipettes: { left: mockAttachedPipetteInformation, right: null },
flowType: FLOWS.ATTACH,
selectedPipette: NINETY_SIX_CHANNEL,
requiredPipette: {
id: '123',
pipetteName: 'p1000_96',
mount: 'left',
},
}
const { getByText, getByAltText, getByRole } = render(props)
getByText('Before you begin')
getByText(
'To get started, remove labware from the deck and clean up the working area to make attachment and calibration easier. Also gather the needed equipment shown to the right.'
)
getByText(
'The calibration probe is included with the robot and should be stored on the front pillar of the robot.'
)
getByText(
'The 96-Channel Pipette is heavy (~10kg). Ask a labmate for help, if needed.'
)
getByAltText('2.5 mm Hex Screwdriver')
getByAltText('Calibration Probe')
getByAltText('Flex 96-Channel 1000 μL')
getByAltText('96-Channel Mounting Plate')
getByText(
'Provided with the robot. Using another size can strip the instruments’s screws.'
)
const proceedBtn = getByRole('button', {
name: 'Move gantry to front',
})
fireEvent.click(proceedBtn)
expect(props.chainRunCommands).toHaveBeenCalledWith(
[
{
commandType: 'loadPipette',
params: {
mount: LEFT,
pipetteId: 'abc',
pipetteName: 'p1000_single_gen3',
},
},
{ commandType: 'home' as const, params: {} },
{
commandType: 'calibration/moveToMaintenancePosition',
params: { mount: LEFT },
},
],
false
)
await waitFor(() => {
expect(props.proceed).toHaveBeenCalled()
})
})
})
describe('detach flow 96 channel', () => {
it('renders the banner for 96 channel with correct info for on device display', () => {
Expand Down
Loading

0 comments on commit 4c68ff5

Please sign in to comment.