diff --git a/app/src/components/CalibratePipetteOffset/__tests__/useCalibratePipetteOffset.test.js b/app/src/components/CalibratePipetteOffset/__tests__/useCalibratePipetteOffset.test.js
index 03f99cc5128c..d91c3afd27ba 100644
--- a/app/src/components/CalibratePipetteOffset/__tests__/useCalibratePipetteOffset.test.js
+++ b/app/src/components/CalibratePipetteOffset/__tests__/useCalibratePipetteOffset.test.js
@@ -1,6 +1,5 @@
// @flow
import * as React from 'react'
-import { Provider } from 'react-redux'
import uniqueId from 'lodash/uniqueId'
import { mountWithStore } from '@opentrons/components/__utils__'
import { act } from 'react-dom/test-utils'
@@ -10,7 +9,6 @@ import * as Sessions from '../../../sessions'
import { mockPipetteOffsetCalibrationSessionAttributes } from '../../../sessions/__fixtures__'
import { useCalibratePipetteOffset } from '../useCalibratePipetteOffset'
-import { mount } from 'enzyme'
import type { State } from '../../../types'
import type { SessionType } from '../../../sessions'
@@ -32,13 +30,20 @@ const mockGetRequestById: JestMockFn<
describe('useCalibratePipetteOffset hook', () => {
let startCalibration
let CalWizardComponent
- let store
const robotName = 'robotName'
const mountString = 'left'
+ const onComplete = jest.fn()
+
const TestUseCalibratePipetteOffset = () => {
const [_startCalibration, _CalWizardComponent] = useCalibratePipetteOffset(
robotName,
- mountString
+ {
+ mount: mountString,
+ shouldPerformTipLength: false,
+ hasCalibrationBlock: false,
+ tipRackDefinition: null,
+ },
+ onComplete
)
React.useEffect(() => {
startCalibration = _startCalibration
@@ -69,7 +74,12 @@ describe('useCalibratePipetteOffset hook', () => {
...Sessions.ensureSession(
robotName,
Sessions.SESSION_TYPE_PIPETTE_OFFSET_CALIBRATION,
- { mount: mountString }
+ {
+ mount: mountString,
+ shouldPerformTipLength: false,
+ hasCalibrationBlock: false,
+ tipRackDefinition: null,
+ }
),
meta: { requestId: expect.any(String) },
})
@@ -85,12 +95,9 @@ describe('useCalibratePipetteOffset hook', () => {
currentStep: Sessions.PIP_OFFSET_STEP_CALIBRATION_COMPLETE,
},
}
- const { store, wrapper } = mountWithStore(
- ,
- {
- initialState: { robotApi: {} },
- }
- )
+ const { wrapper } = mountWithStore(, {
+ initialState: { robotApi: {} },
+ })
mockGetRobotSessionOfType.mockReturnValue(mockPipOffsetCalSession)
mockGetRequestById.mockReturnValue({
status: RobotApi.SUCCESS,
@@ -105,8 +112,11 @@ describe('useCalibratePipetteOffset hook', () => {
wrapper.setProps({})
expect(CalWizardComponent).not.toBe(null)
- wrapper.find('button[children="exit"]').invoke('onClick')()
+ wrapper
+ .find('button[title="Return tip to tip rack and exit"]')
+ .invoke('onClick')()
wrapper.setProps({})
expect(CalWizardComponent).toBe(null)
+ expect(onComplete).toHaveBeenCalled()
})
})
diff --git a/app/src/components/CalibratePipetteOffset/useCalibratePipetteOffset.js b/app/src/components/CalibratePipetteOffset/useCalibratePipetteOffset.js
index 0083cd5093cc..4881b9244a15 100644
--- a/app/src/components/CalibratePipetteOffset/useCalibratePipetteOffset.js
+++ b/app/src/components/CalibratePipetteOffset/useCalibratePipetteOffset.js
@@ -1,7 +1,6 @@
// @flow
import * as React from 'react'
import { useSelector } from 'react-redux'
-import { SecondaryBtn, SPACING_2 } from '@opentrons/components'
import * as RobotApi from '../../robot-api'
import * as Sessions from '../../sessions'
@@ -10,8 +9,8 @@ import type { State } from '../../types'
import type {
SessionCommandString,
PipetteOffsetCalibrationSession,
+ PipetteOffsetCalibrationSessionParams,
} from '../../sessions/types'
-import type { Mount } from '../../pipettes/types'
import type { RequestState } from '../../robot-api/types'
import { Portal } from '../portal'
@@ -24,7 +23,7 @@ const spinnerCommandBlockList: Array = [
export function useCalibratePipetteOffset(
robotName: string,
- mount: Mount,
+ sessionParams: $Shape,
onComplete: (() => mixed) | null = null
): [() => void, React.Node | null] {
const [showWizard, setShowWizard] = React.useState(false)
@@ -74,24 +73,47 @@ export function useCalibratePipetteOffset(
: null
)?.status === RobotApi.SUCCESS
+ const closeWizard = React.useCallback(() => {
+ setShowWizard(false)
+ onComplete && onComplete()
+ }, [onComplete])
+
React.useEffect(() => {
if (shouldOpen) {
setShowWizard(true)
createRequestId.current = null
}
if (shouldClose) {
- setShowWizard(false)
- onComplete && onComplete()
+ closeWizard()
deleteRequestId.current = null
}
- }, [shouldOpen, shouldClose])
+ }, [shouldOpen, shouldClose, closeWizard])
+ const {
+ mount,
+ shouldPerformTipLength = false,
+ hasCalibrationBlock = false,
+ tipRackDefinition = null,
+ } = sessionParams
const handleStartPipOffsetCalSession = () => {
+ console.log('HANDLE START')
+ console.table({
+ robotName,
+ mount,
+ shouldPerformTipLength,
+ hasCalibrationBlock,
+ tipRackDefinition,
+ })
dispatchRequests(
Sessions.ensureSession(
robotName,
Sessions.SESSION_TYPE_PIPETTE_OFFSET_CALIBRATION,
- { mount }
+ {
+ mount,
+ shouldPerformTipLength,
+ hasCalibrationBlock,
+ tipRackDefinition,
+ }
)
)
}
@@ -118,7 +140,7 @@ export function useCalibratePipetteOffset(
setShowWizard(false)}
+ closeWizard={closeWizard}
showSpinner={showSpinner}
dispatchRequests={dispatchRequests}
/>
diff --git a/app/src/components/ChangePipette/ConfirmPipette.js b/app/src/components/ChangePipette/ConfirmPipette.js
index d3d3bc8262f7..01b7a3f16118 100644
--- a/app/src/components/ChangePipette/ConfirmPipette.js
+++ b/app/src/components/ChangePipette/ConfirmPipette.js
@@ -2,14 +2,7 @@
import * as React from 'react'
import cx from 'classnames'
-import {
- Icon,
- PrimaryBtn,
- ModalPage,
- SPACING_2,
- SPACING_4,
-} from '@opentrons/components'
-import { PipetteOffsetCalibrationControl } from '../InstrumentSettings/PipetteOffsetCalibrationControl'
+import { Icon, PrimaryBtn, ModalPage, SPACING_2 } from '@opentrons/components'
import { getDiagramsSrc } from './InstructionStep'
import { CheckPipettesButton } from './CheckPipettesButton'
import styles from './styles.css'
@@ -21,7 +14,6 @@ import type {
} from '@opentrons/shared-data'
import type { Mount } from '../../pipettes/types'
import type { PipetteOffsetCalibration } from '../../calibration/types'
-import { CalibratePipetteOffset } from '../CalibratePipetteOffset'
const EXIT_BUTTON_MESSAGE = 'exit pipette setup'
const EXIT_BUTTON_MESSAGE_WRONG = 'keep pipette and exit setup'
@@ -54,9 +46,6 @@ export function ConfirmPipette(props: Props): React.Node {
actualPipette,
actualPipetteOffset,
back,
- robotName,
- mount,
- startPipetteOffsetCalibration,
} = props
return (
diff --git a/app/src/components/ChangePipette/index.js b/app/src/components/ChangePipette/index.js
index a7f70524e60c..add428ec0e88 100644
--- a/app/src/components/ChangePipette/index.js
+++ b/app/src/components/ChangePipette/index.js
@@ -1,10 +1,13 @@
// @flow
import * as React from 'react'
import { useSelector, useDispatch } from 'react-redux'
-import last from 'lodash/last'
import { getPipetteNameSpecs, shouldLevel } from '@opentrons/shared-data'
-import { useDispatchApiRequest, getRequestById, PENDING } from '../../robot-api'
+import {
+ useDispatchApiRequests,
+ getRequestById,
+ SUCCESS,
+} from '../../robot-api'
import { getCalibrationForPipette } from '../../calibration'
import { getAttachedPipettes } from '../../pipettes'
import {
@@ -13,8 +16,10 @@ import {
getMovementStatus,
HOMING,
MOVING,
+ ROBOT,
PIPETTE,
CHANGE_PIPETTE,
+ HOME,
} from '../../robot-controls'
import { useCalibratePipetteOffset } from '../CalibratePipetteOffset'
@@ -53,7 +58,16 @@ const MOUNT = 'mount'
export function ChangePipette(props: Props): React.Node {
const { robotName, mount, closeModal } = props
const dispatch = useDispatch()
- const [dispatchApiRequest, requestIds] = useDispatchApiRequest()
+ const homePipRequestId = React.useRef(null)
+ const [dispatchApiRequests] = useDispatchApiRequests(dispatchedAction => {
+ if (
+ dispatchedAction.type === HOME &&
+ dispatchedAction.payload.target === PIPETTE
+ ) {
+ // track final home pipette request, its success closes modal
+ homePipRequestId.current = dispatchedAction.meta.requestId
+ }
+ })
const [wizardStep, setWizardStep] = React.useState(CLEAR_DECK)
const [wantedName, setWantedName] = React.useState(null)
const [confirmExit, setConfirmExit] = React.useState(false)
@@ -72,25 +86,28 @@ export function ChangePipette(props: Props): React.Node {
return getMovementStatus(state, robotName)
})
- const homeRequest = useSelector((state: State) => {
- return getRequestById(state, last(requestIds))
- })?.status
+ const homePipSuccess =
+ useSelector((state: State) => {
+ return homePipRequestId.current
+ ? getRequestById(state, homePipRequestId.current)
+ : null
+ })?.status === SUCCESS
React.useEffect(() => {
- if (homeRequest && homeRequest !== PENDING) {
+ if (homePipSuccess) {
closeModal()
}
- }, [homeRequest, closeModal])
+ }, [homePipSuccess, closeModal])
- const homeAndExit = React.useCallback(
- () => dispatchApiRequest(home(robotName, PIPETTE, mount)),
- [dispatchApiRequest, robotName, mount]
+ const homePipAndExit = React.useCallback(
+ () => dispatchApiRequests(home(robotName, PIPETTE, mount)),
+ [dispatchApiRequests, robotName, mount]
)
const [
startPipetteOffsetCalibration,
PipetteOffsetCalibrationWizard,
- ] = useCalibratePipetteOffset(robotName, mount, closeModal)
+ ] = useCalibratePipetteOffset(robotName, { mount }, closeModal)
const baseProps = {
title: PIPETTE_SETUP,
@@ -139,7 +156,7 @@ export function ChangePipette(props: Props): React.Node {
{confirmExit && (
setConfirmExit(false)}
- exit={homeAndExit}
+ exit={homePipAndExit}
/>
)}
{
+ // home before cal flow to account for skips when attaching pipette
+ setWizardStep(CALIBRATE_PIPETTE)
+ dispatchApiRequests(home(robotName, ROBOT))
+ startPipetteOffsetCalibration()
+ }
+
if (success && wantedPipette && shouldLevel(wantedPipette)) {
return (
setWizardStep(INSTRUCTIONS),
- exit: homeAndExit,
+ exit: homePipAndExit,
actualPipetteOffset: actualPipetteOffset,
- startPipetteOffsetCalibration: () => {
- startPipetteOffsetCalibration()
- setWizardStep(CALIBRATE_PIPETTE)
- },
+ startPipetteOffsetCalibration: launchPOC,
}}
/>
)
@@ -192,12 +213,9 @@ export function ChangePipette(props: Props): React.Node {
setWizardStep(INSTRUCTIONS)
},
back: () => setWizardStep(INSTRUCTIONS),
- exit: homeAndExit,
+ exit: homePipAndExit,
actualPipetteOffset: actualPipetteOffset,
- startPipetteOffsetCalibration: () => {
- startPipetteOffsetCalibration()
- setWizardStep(CALIBRATE_PIPETTE)
- },
+ startPipetteOffsetCalibration: launchPOC,
}}
/>
)
diff --git a/app/src/components/InstrumentSettings/PipetteInfo.js b/app/src/components/InstrumentSettings/PipetteInfo.js
index 4f042c70c2bd..91f6d432a848 100644
--- a/app/src/components/InstrumentSettings/PipetteInfo.js
+++ b/app/src/components/InstrumentSettings/PipetteInfo.js
@@ -68,7 +68,7 @@ export function PipetteInfo(props: PipetteInfoProps): React.Node {
const [
startPipetteOffsetCalibration,
PipetteOffsetCalibrationWizard,
- ] = useCalibratePipetteOffset(robotName, mount)
+ ] = useCalibratePipetteOffset(robotName, { mount })
const pipImage = (
= [
- Sessions.sharedCalCommands.JOG,
-]
-
-const BUTTON_TEXT = 'Calibrate offset'
-
-export function PipetteOffsetCalibrationControl(props: Props): React.Node {
- const { robotName, mount } = props
-
- const [showWizard, setShowWizard] = React.useState(false)
-
- const trackedRequestId = React.useRef(null)
- const deleteRequestId = React.useRef(null)
- const createRequestId = React.useRef(null)
-
- const [dispatchRequests] = RobotApi.useDispatchApiRequests(
- dispatchedAction => {
- if (dispatchedAction.type === Sessions.ENSURE_SESSION) {
- createRequestId.current = dispatchedAction.meta.requestId
- } else if (
- dispatchedAction.type === Sessions.DELETE_SESSION &&
- pipOffsetCalSession?.id === dispatchedAction.payload.sessionId
- ) {
- deleteRequestId.current = dispatchedAction.meta.requestId
- } else if (
- dispatchedAction.type !== Sessions.CREATE_SESSION_COMMAND ||
- !spinnerCommandBlockList.includes(
- dispatchedAction.payload.command.command
- )
- ) {
- trackedRequestId.current = dispatchedAction.meta.requestId
- }
- }
- )
-
- const showSpinner =
- useSelector(state =>
- trackedRequestId.current
- ? RobotApi.getRequestById(state, trackedRequestId.current)
- : null
- )?.status === RobotApi.PENDING
-
- const shouldClose =
- useSelector(state =>
- deleteRequestId.current
- ? RobotApi.getRequestById(state, deleteRequestId.current)
- : null
- )?.status === RobotApi.SUCCESS
-
- const shouldOpen =
- useSelector((state: State) =>
- createRequestId.current
- ? RobotApi.getRequestById(state, createRequestId.current)
- : null
- )?.status === RobotApi.SUCCESS
-
- React.useEffect(() => {
- if (shouldOpen) {
- setShowWizard(true)
- createRequestId.current = null
- }
- if (shouldClose) {
- setShowWizard(false)
- deleteRequestId.current = null
- }
- }, [shouldOpen, shouldClose])
-
- const hasCalibrationBlock = false
- const shouldPerformTipLength = false
- const tipRackDefinition = null
- const handleStartPipOffsetCalSession = () => {
- dispatchRequests(
- Sessions.ensureSession(
- robotName,
- Sessions.SESSION_TYPE_PIPETTE_OFFSET_CALIBRATION,
- {
- mount,
- shouldPerformTipLength,
- hasCalibrationBlock,
- tipRackDefinition,
- }
- )
- )
- }
-
- const pipOffsetCalSession = useSelector<
- State,
- PipetteOffsetCalibrationSession | null
- >((state: State) => {
- const session: Sessions.Session | null = Sessions.getRobotSessionOfType(
- state,
- robotName,
- Sessions.SESSION_TYPE_PIPETTE_OFFSET_CALIBRATION
- )
- return session &&
- session.sessionType === Sessions.SESSION_TYPE_PIPETTE_OFFSET_CALIBRATION
- ? session
- : null
- })
-
- const [
- startPipetteOffsetCalibration,
- PipetteOffsetCalibrationWizard,
- ] = useCalibratePipetteOffset()
-
- return (
- <>
-
- {BUTTON_TEXT}
-
- {showWizard && (
-
- setShowWizard(false)}
- showSpinner={showSpinner}
- dispatchRequests={dispatchRequests}
- />
-
- )}
- >
- )
-}