From b88c73ba9a79758cf130d2c24d8700aa5c13bcc8 Mon Sep 17 00:00:00 2001 From: Mike Cousins Date: Wed, 28 Aug 2019 15:00:26 -0400 Subject: [PATCH] fix(app): Improve tip probe wizard state and error handling (#3959) Closes #3948, closes #3944, closes #3943, closes #2008 --- CONTRIBUTING.md | 2 +- .../img/trash@3x.png | Bin .../components/ClearDeckAlertModal/index.js | 31 +++--- .../components/ClearDeckAlertModal/styles.css | 13 ++- .../ConfirmTipProbeModal/Contents.css | 26 ----- .../ConfirmTipProbeModal/Contents.js | 19 ---- .../components/ConfirmTipProbeModal/index.js | 50 ---------- app/src/components/TipProbe/AttachTipPanel.js | 17 +++- app/src/components/TipProbe/UnprobedPanel.js | 91 ++++++++---------- app/src/components/TipProbe/index.js | 71 +++++++++++--- app/src/components/TipProbe/tip-probe.css | 6 ++ app/src/components/TipProbe/types.js | 13 ++- app/src/pages/Calibrate/Pipettes.js | 22 +---- app/src/robot/actions.js | 20 ++-- app/src/robot/constants.js | 9 -- app/src/robot/reducer/calibration.js | 19 ++-- app/src/robot/selectors.js | 22 ----- app/src/robot/test/selectors.test.js | 8 -- app/src/robot/types.js | 11 --- 19 files changed, 189 insertions(+), 261 deletions(-) rename app/src/components/{ConfirmTipProbeModal => ClearDeckAlertModal}/img/trash@3x.png (100%) delete mode 100644 app/src/components/ConfirmTipProbeModal/Contents.css delete mode 100644 app/src/components/ConfirmTipProbeModal/Contents.js delete mode 100644 app/src/components/ConfirmTipProbeModal/index.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2525eb3ffa..8f3f65532bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -377,7 +377,7 @@ make term make term host=${some_other_ip_address} ``` -If `make term` complains about not having a key, you may need to install a public key on the robot. To do this, create an ssh key and install it: +If `make term` complains about not having a key, you may need to install a public key on the robot. To do this, create an ssh key and install it: ```shell ssh-keygen # note the path you save the key to diff --git a/app/src/components/ConfirmTipProbeModal/img/trash@3x.png b/app/src/components/ClearDeckAlertModal/img/trash@3x.png similarity index 100% rename from app/src/components/ConfirmTipProbeModal/img/trash@3x.png rename to app/src/components/ClearDeckAlertModal/img/trash@3x.png diff --git a/app/src/components/ClearDeckAlertModal/index.js b/app/src/components/ClearDeckAlertModal/index.js index bf765243b91..bcd7699771d 100644 --- a/app/src/components/ClearDeckAlertModal/index.js +++ b/app/src/components/ClearDeckAlertModal/index.js @@ -4,17 +4,20 @@ import { Link } from 'react-router-dom' import { AlertModal } from '@opentrons/components' import { Portal } from '../portal' +import removeTrashSrc from './img/trash@3x.png' import styles from './styles.css' -type Props = { +type Props = {| onContinueClick?: () => mixed, onCancelClick?: () => mixed, - parentUrl: string, + parentUrl?: string, cancelText: string, continueText: string, + removeTrash?: boolean, children?: React.Node, -} -const HEADING = 'Before continuing, remove from deck:' +|} + +const HEADING = 'Before continuing, please remove:' export default function ClearDeckAlertModal(props: Props) { const { @@ -23,6 +26,7 @@ export default function ClearDeckAlertModal(props: Props) { parentUrl, cancelText, continueText, + removeTrash = false, } = props return ( @@ -32,9 +36,8 @@ export default function ClearDeckAlertModal(props: Props) { buttons={[ { children: `${cancelText}`, - Component: Link, - to: parentUrl, onClick: onCancelClick, + ...(parentUrl != null ? { Component: Link, to: parentUrl } : {}), }, { children: `${continueText}`, @@ -44,11 +47,17 @@ export default function ClearDeckAlertModal(props: Props) { ]} alertOverlay > - - {props.children && ( +
+ + {removeTrash && ( + + )} +
+ {props.children != null && (

Note:

{props.children} diff --git a/app/src/components/ClearDeckAlertModal/styles.css b/app/src/components/ClearDeckAlertModal/styles.css index bef6c75f66b..d79b618600d 100644 --- a/app/src/components/ClearDeckAlertModal/styles.css +++ b/app/src/components/ClearDeckAlertModal/styles.css @@ -1,8 +1,15 @@ @import '@opentrons/components'; +.alert_instructions { + display: flex; + flex-wrap: wrap; + align-items: center; +} + .alert_list { + padding-left: 1rem; + padding-right: 4rem; list-style-type: none; - padding-left: 3rem; & > li { line-height: 2; @@ -15,6 +22,10 @@ } } +.alert_diagram { + max-height: 10rem; +} + .alert_note_heading { @apply --font-body-2-dark; diff --git a/app/src/components/ConfirmTipProbeModal/Contents.css b/app/src/components/ConfirmTipProbeModal/Contents.css deleted file mode 100644 index f256155a5be..00000000000 --- a/app/src/components/ConfirmTipProbeModal/Contents.css +++ /dev/null @@ -1,26 +0,0 @@ -/* style for ContinueTipProbeModal contents */ -@import '@opentrons/components'; - -.attention { - @apply --font-header-dark; - - margin-bottom: 1rem; -} - -.list { - @apply --font-body-2-dark; - - list-style: none; - padding-left: 2rem; - display: inline-block; - vertical-align: top; - margin-right: 2rem; -} - -.list li { - margin-top: 0.75rem; -} - -.diagram { - max-width: 40%; -} diff --git a/app/src/components/ConfirmTipProbeModal/Contents.js b/app/src/components/ConfirmTipProbeModal/Contents.js deleted file mode 100644 index 44139efe0ee..00000000000 --- a/app/src/components/ConfirmTipProbeModal/Contents.js +++ /dev/null @@ -1,19 +0,0 @@ -// @flow -// contents of the ContinueTipProbeModal container -import * as React from 'react' - -import removeTrashSrc from './img/trash@3x.png' -import styles from './Contents.css' - -export default function Contents() { - return ( -
-

Before continuing remove from deck:

-
    -
  1. All labware
  2. -
  3. Trash bin
  4. -
- -
- ) -} diff --git a/app/src/components/ConfirmTipProbeModal/index.js b/app/src/components/ConfirmTipProbeModal/index.js deleted file mode 100644 index bc5408c5cb4..00000000000 --- a/app/src/components/ConfirmTipProbeModal/index.js +++ /dev/null @@ -1,50 +0,0 @@ -// @flow -// container to prompt the user to clear the deck before continuing tip probe -import * as React from 'react' -import { connect } from 'react-redux' -import { push } from 'connected-react-router' - -import { actions as robotActions, type Mount } from '../../robot' -import { ContinueModal } from '@opentrons/components' -import { Portal } from '../portal' -import Contents from './Contents' - -import type { Dispatch } from '../../types' - -type OP = {| mount: Mount, backUrl: string |} - -type DP = {| onContinueClick: () => mixed, onCancelClick: () => mixed |} - -type Props = { ...OP, ...DP } - -export default connect( - null, - mapDispatchToProps -)(ContinueTipProbeModal) - -function ContinueTipProbeModal(props: Props) { - return ( - - - - - - ) -} - -function mapDispatchToProps(dispatch: Dispatch, ownProps: OP): DP { - const { mount, backUrl } = ownProps - - return { - // TODO(mc, 2018-01-23): refactor to remove double dispatch - onContinueClick: () => { - // $FlowFixMe: robotActions.moveToFront is not typed - dispatch(robotActions.moveToFront(mount)) - dispatch(push(backUrl)) - }, - onCancelClick: () => dispatch(push(backUrl)), - } -} diff --git a/app/src/components/TipProbe/AttachTipPanel.js b/app/src/components/TipProbe/AttachTipPanel.js index 3c2eb6589ee..a3c9c7a7b24 100644 --- a/app/src/components/TipProbe/AttachTipPanel.js +++ b/app/src/components/TipProbe/AttachTipPanel.js @@ -1,6 +1,8 @@ // @flow import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' +import cx from 'classnames' + import CalibrationInfoContent from '../CalibrationInfoContent' import { PrimaryButton } from '@opentrons/components' @@ -10,6 +12,7 @@ import { } from '../../robot' import attachSingle from '../../img/attach_tip_single.png' import attachMulti from '../../img/attach_tip_multi.png' +import styles from './tip-probe.css' import type { Dispatch } from '../../types' import type { TipProbeProps } from './types' @@ -26,6 +29,7 @@ export default function AttachTipPanel(props: Props) { // $FlowFixMe: robotActions.probeTip is not typed const handleTipProbe = () => dispatch(robotActions.probeTip(mount)) + const isMulti = channels > 1 const leftChildren = (
@@ -39,7 +43,8 @@ export default function AttachTipPanel(props: Props) {
{' '} )} - on pipette before continuing + on {isMulti ? 'the back-most channel of' : ''} the pipette before + continuing

Confirm Tip Attached @@ -47,9 +52,15 @@ export default function AttachTipPanel(props: Props) {
) - const imgSrc = channels === 1 ? attachSingle : attachMulti + const imgSrc = isMulti ? attachMulti : attachSingle - const rightChildren = attach tip + const rightChildren = ( + attach tip + ) return ( void |} +export default function UnprobedPanel(props: TipProbeProps) { + const { mount, probed } = props + const [showClearDeck, setShowClearDeck] = React.useState(false) + const dispatch = useDispatch() + const deckPopulated = useSelector(getDeckPopulated) -export default connect( - mapStateToProps, - null, - mergeProps -)(UnprobedPanel) + const moveToFront = () => { + // $FlowFixMe: robotActions.moveToFront is not typed + dispatch(robotActions.moveToFront(mount)) + setShowClearDeck(false) + } -function UnprobedPanel(props: Props) { - const { probed, onPrepareClick } = props + const handleStart = () => { + if (deckPopulated === true || deckPopulated === null) { + setShowClearDeck(true) + } else { + moveToFront() + } + } const message = !probed ? 'Pipette tip is not calibrated' @@ -40,37 +42,22 @@ function UnprobedPanel(props: Props) { const leftChildren = (

{message}

- {buttonText} + {buttonText}
) - return -} - -function mapStateToProps(state, ownProps: OP): SP { - const deckPopulated = robotSelectors.getDeckPopulated(state) - - return { - _showContinueModal: deckPopulated === true || deckPopulated === null, - } -} - -function mergeProps(stateProps: SP, dispatchProps: DP, ownProps: OP): Props { - const { _showContinueModal } = stateProps - const { dispatch } = dispatchProps - const { mount, confirmTipProbeUrl } = ownProps - - const onPrepareClick = _showContinueModal - ? () => { - dispatch(push(confirmTipProbeUrl)) - } - : () => { - // $FlowFixMe: robotActions.moveToFront is not typed - dispatch(robotActions.moveToFront(mount)) - } - - return { - ...ownProps, - onPrepareClick, - } + return ( + <> + + {showClearDeck && ( + setShowClearDeck(false)} + removeTrash + /> + )} + + ) } diff --git a/app/src/components/TipProbe/index.js b/app/src/components/TipProbe/index.js index 6b2889c5b11..2a45dd8f42c 100644 --- a/app/src/components/TipProbe/index.js +++ b/app/src/components/TipProbe/index.js @@ -1,10 +1,13 @@ // @flow // TipProbe controls import * as React from 'react' +import { useSelector, useDispatch } from 'react-redux' -import type { PipetteCalibrationStatus } from '../../robot' -import type { TipProbeProps } from './types' +import { usePrevious } from '@opentrons/components' +import { actions as robotActions } from '../../robot' +import { getCalibrationRequest } from '../../robot/selectors' +import { ErrorModal } from '../modals' import CalibrationInfoBox from '../CalibrationInfoBox' import UnprobedPanel from './UnprobedPanel' import InstrumentMovingPanel from './InstrumentMovingPanel' @@ -12,26 +15,70 @@ import AttachTipPanel from './AttachTipPanel' import RemoveTipPanel from './RemoveTipPanel' import ContinuePanel from './ContinuePanel' +import type { Dispatch } from '../../types' +import type { TipProbeProps, TipProbeState } from './types' + +const PROBE_ERROR_HEADING = 'Error during tip probe' +const PROBE_ERROR_DESCRIPTION = + 'The above error occurred while attempting to tip probe. Please try again.' + const PANEL_BY_CALIBRATION: { - [PipetteCalibrationStatus]: React.ComponentType, + [TipProbeState]: React.ComponentType, } = { unprobed: UnprobedPanel, - 'preparing-to-probe': InstrumentMovingPanel, - 'ready-to-probe': AttachTipPanel, + 'moving-to-front': InstrumentMovingPanel, + 'waiting-for-tip': AttachTipPanel, probing: InstrumentMovingPanel, - 'probed-tip-on': RemoveTipPanel, - probed: ContinuePanel, + 'waiting-for-remove-tip': RemoveTipPanel, + done: ContinuePanel, } export default function TipProbe(props: TipProbeProps) { - const { mount, probed, calibration } = props + const { mount, probed } = props + const dispatch = useDispatch() + const [probeState, setProbeState] = React.useState('unprobed') + const prevProbeState = usePrevious(probeState) const title = `${mount} pipette calibration` + const Panel = PANEL_BY_CALIBRATION[probeState] + const calRequest = useSelector(getCalibrationRequest) + + React.useEffect(() => { + const { mount: calMount, type: calType, inProgress, error } = calRequest + let nextProbeState = 'unprobed' + + if (!error && calMount === mount) { + if (calType === 'MOVE_TO_FRONT') { + nextProbeState = inProgress ? 'moving-to-front' : 'waiting-for-tip' + } else if (calType === 'PROBE_TIP') { + if (inProgress) { + nextProbeState = 'probing' + } else if (!probed) { + nextProbeState = 'waiting-for-remove-tip' + } else if ( + prevProbeState === 'waiting-for-remove-tip' || + prevProbeState === 'done' + ) { + nextProbeState = 'done' + } + } + } - const Panel = PANEL_BY_CALIBRATION[calibration] + setProbeState(nextProbeState) + }, [calRequest, mount, probed, prevProbeState]) return ( - - - + <> + + + + {calRequest.error !== null && ( + dispatch(robotActions.clearCalibrationRequest())} + /> + )} + ) } diff --git a/app/src/components/TipProbe/tip-probe.css b/app/src/components/TipProbe/tip-probe.css index e8711d00344..515bc1b5450 100644 --- a/app/src/components/TipProbe/tip-probe.css +++ b/app/src/components/TipProbe/tip-probe.css @@ -8,3 +8,9 @@ float: right; margin-right: calc(-12.5% - 1.5rem); } + +.pipette_diagram { + &.right { + transform: scaleX(-1); + } +} diff --git a/app/src/components/TipProbe/types.js b/app/src/components/TipProbe/types.js index 6b21ebe443a..9708326fe23 100644 --- a/app/src/components/TipProbe/types.js +++ b/app/src/components/TipProbe/types.js @@ -1,7 +1,12 @@ // @flow import type { Pipette } from '../../robot' -export type TipProbeProps = {| - ...$Exact, - confirmTipProbeUrl: string, -|} +export type TipProbeProps = $Exact + +export type TipProbeState = + | 'unprobed' + | 'moving-to-front' + | 'waiting-for-tip' + | 'probing' + | 'waiting-for-remove-tip' + | 'done' diff --git a/app/src/pages/Calibrate/Pipettes.js b/app/src/pages/Calibrate/Pipettes.js index 2365fb9dd21..e08103e44f7 100644 --- a/app/src/pages/Calibrate/Pipettes.js +++ b/app/src/pages/Calibrate/Pipettes.js @@ -2,7 +2,7 @@ // setup pipettes component import * as React from 'react' import { connect } from 'react-redux' -import { Route, Redirect } from 'react-router' +import { Redirect } from 'react-router' import { selectors as robotSelectors } from '../../robot' import { getPipettesState, fetchPipettes } from '../../robot-api' @@ -10,7 +10,6 @@ import { getConnectedRobot } from '../../discovery' import Page, { RefreshWrapper } from '../../components/Page' import TipProbe from '../../components/TipProbe' -import ConfirmTipProbeModal from '../../components/ConfirmTipProbeModal' import { PipetteTabs, Pipettes } from '../../components/calibrate-pipettes' import SessionHeader from '../../components/SessionHeader' @@ -55,7 +54,6 @@ function CalibratePipettesPage(props: Props) { match: { url, params }, changePipetteUrl, } = props - const confirmTipProbeUrl = `${url}/confirm-tip-probe` // redirect back to mountless route if mount doesn't exist if (params.mount && !currentPipette) { @@ -75,23 +73,7 @@ function CalibratePipettesPage(props: Props) { changePipetteUrl, }} /> - {!!currentPipette && ( - - )} - {!!currentPipette && ( - ( - - )} - /> - )} + {!!currentPipette && } ) diff --git a/app/src/robot/actions.js b/app/src/robot/actions.js index 4c01f1761db..7578954e3e1 100755 --- a/app/src/robot/actions.js +++ b/app/src/robot/actions.js @@ -2,6 +2,7 @@ // robot actions and action types import { _NAME as NAME } from './constants' +import type { Error } from '../types' import type { ProtocolData } from '../protocol' import type { Mount, Slot, Axis, Direction, SessionUpdate } from './types' @@ -9,8 +10,6 @@ import type { Mount, Slot, Axis, Direction, SessionUpdate } from './types' const makeRobotActionName = action => `${NAME}:${action}` const tagForRobotApi = action => ({ ...action, meta: { robotCommand: true } }) -type Error = { message: string } - export type ConnectAction = {| type: 'robot:CONNECT', payload: {| @@ -99,7 +98,7 @@ export type LabwareCalibrationAction = {| |}, |} -export type CalibrationSuccessAction = { +export type CalibrationSuccessAction = {| type: | 'robot:MOVE_TO_SUCCESS' | 'robot:JOG_SUCCESS' @@ -112,7 +111,7 @@ export type CalibrationSuccessAction = { isTiprack?: boolean, tipOn?: boolean, }, -} +|} export type CalibrationFailureAction = {| type: @@ -162,10 +161,14 @@ export type CalibrationResponseAction = | CalibrationSuccessAction | CalibrationFailureAction -export type SetModulesReviewedAction = { +export type SetModulesReviewedAction = {| type: 'robot:SET_MODULES_REVIEWED', payload: boolean, -} +|} + +export type ClearCalibrationRequestAction = {| + type: 'robot:CLEAR_CALIBRATION_REQUEST', +|} // TODO(mc, 2018-01-23): refactor to use type above // DO NOT ADD NEW ACTIONS HERE @@ -215,6 +218,7 @@ export type Action = | SessionUpdateAction | RefreshSessionAction | SetModulesReviewedAction + | ClearCalibrationRequestAction export const actions = { connect(name: string): ConnectAction { @@ -556,4 +560,8 @@ export const actions = { tickRunTime() { return { type: actionTypes.TICK_RUN_TIME } }, + + clearCalibrationRequest(): ClearCalibrationRequestAction { + return { type: 'robot:CLEAR_CALIBRATION_REQUEST' } + }, } diff --git a/app/src/robot/constants.js b/app/src/robot/constants.js index ac8e59b5f93..3a441667393 100755 --- a/app/src/robot/constants.js +++ b/app/src/robot/constants.js @@ -22,15 +22,6 @@ export const RUNNING = 'running' export const PAUSED = 'paused' export const FINISHED = 'finished' -// tip probe calibration states -// TODO(mc, 2018-01-22): remove constant exports in favor of flowtype -// see types.js -export const UNPROBED = 'unprobed' -export const PREPARING_TO_PROBE = 'preparing-to-probe' -export const READY_TO_PROBE = 'ready-to-probe' -export const PROBING = 'probing' -export const PROBED = 'probed' - // labware confirmation states // TODO(mc, 2018-01-11): remove constant exports in favor of types.js export const UNCONFIRMED = 'unconfirmed' diff --git a/app/src/robot/reducer/calibration.js b/app/src/robot/reducer/calibration.js index 71edd5c0bb1..ac0e9431fca 100755 --- a/app/src/robot/reducer/calibration.js +++ b/app/src/robot/reducer/calibration.js @@ -3,7 +3,7 @@ // TODO(mc, 2018-01-10): refactor to use combineReducers import mapValues from 'lodash/mapValues' -import type { Action } from '../../types' +import type { Action, Error } from '../../types' import type { Mount, Slot } from '../types' import { actionTypes } from '../actions' import type { @@ -30,15 +30,15 @@ type CalibrationRequestType = | 'UPDATE_OFFSET' | 'SET_MODULES_REVIEWED' -type CalibrationRequest = { +type CalibrationRequest = $ReadOnly<{| type: CalibrationRequestType, mount?: Mount, slot?: Slot, inProgress: boolean, - error: ?{ message: string }, -} + error: Error | null, +|}> -export type CalibrationState = $ReadOnly<{ +export type CalibrationState = $ReadOnly<{| deckPopulated: ?boolean, modulesReviewed: ?boolean, @@ -48,7 +48,7 @@ export type CalibrationState = $ReadOnly<{ confirmedBySlot: { [Slot]: boolean }, calibrationRequest: CalibrationRequest, -}> +|}> // TODO(mc, 2018-01-11): replace actionType constants with Flow types const { @@ -83,6 +83,13 @@ export default function calibrationReducer( case 'protocol:UPLOAD': return INITIAL_STATE + // reset calibration state on robot home + case 'robot:CLEAR_CALIBRATION_REQUEST': + return { + ...state, + calibrationRequest: { type: '', inProgress: false, error: null }, + } + case 'robot:CONFIRM_PROBED': return handleConfirmProbed(state, action) diff --git a/app/src/robot/selectors.js b/app/src/robot/selectors.js index 687e19f6230..39c433def36 100644 --- a/app/src/robot/selectors.js +++ b/app/src/robot/selectors.js @@ -15,7 +15,6 @@ import type { Mount, Slot, Pipette, - PipetteCalibrationStatus, Labware, LabwareCalibrationStatus, LabwareType, @@ -229,32 +228,11 @@ export const getPipettes: OutputSelector< return PIPETTE_MOUNTS.filter(mount => pipettesByMount[mount] != null).map( mount => { const pipette = pipettesByMount[mount] - const probed = probedByMount[mount] || false const tipOn = tipOnByMount[mount] || false - let calibration: PipetteCalibrationStatus = 'unprobed' - - // TODO(mc: 2018-01-10): rethink pipette level "calibration" prop - // TODO(mc: 2018-01-23): handle probe error state better - if (calibrationRequest.mount === mount && !calibrationRequest.error) { - if (calibrationRequest.type === 'MOVE_TO_FRONT') { - calibration = calibrationRequest.inProgress - ? 'preparing-to-probe' - : 'ready-to-probe' - } else if (calibrationRequest.type === 'PROBE_TIP') { - if (calibrationRequest.inProgress) { - calibration = 'probing' - } else if (!probed) { - calibration = 'probed-tip-on' - } else { - calibration = 'probed' - } - } - } return { ...pipette, - calibration, probed, tipOn, modelSpecs: getPipetteModelSpecs(pipette.name) || null, diff --git a/app/src/robot/test/selectors.test.js b/app/src/robot/test/selectors.test.js index 80c2c8b9aaf..06e56540903 100644 --- a/app/src/robot/test/selectors.test.js +++ b/app/src/robot/test/selectors.test.js @@ -344,12 +344,6 @@ describe('robot selectors', () => { }, }, calibration: { - calibrationRequest: { - type: 'PROBE_TIP', - mount: 'left', - inProgress: true, - error: null, - }, probedByMount: { left: true, }, @@ -368,7 +362,6 @@ describe('robot selectors', () => { name: 'p200m', channels: 8, volume: 200, - calibration: constants.PROBING, probed: true, tipOn: false, modelSpecs: null, @@ -378,7 +371,6 @@ describe('robot selectors', () => { name: 'p50s', channels: 1, volume: 50, - calibration: constants.UNPROBED, probed: false, tipOn: true, modelSpecs: null, diff --git a/app/src/robot/types.js b/app/src/robot/types.js index 53ed0c408df..3506410b91c 100644 --- a/app/src/robot/types.js +++ b/app/src/robot/types.js @@ -45,16 +45,6 @@ export type RobotService = { port: number, } -// TODO(mc, 2018-01-22): pay attention to this when deprecating status contants -// in constants.js. Also re-evaluate the need for this logic / type -export type PipetteCalibrationStatus = - | 'unprobed' - | 'preparing-to-probe' - | 'ready-to-probe' - | 'probing' - | 'probed-tip-on' - | 'probed' - // TODO(mc, 2018-01-11): collapse a bunch of these into something like MOVING export type LabwareCalibrationStatus = | 'unconfirmed' @@ -101,7 +91,6 @@ export type StatePipette = { export type Pipette = { ...$Exact, - calibration: PipetteCalibrationStatus, probed: boolean, tipOn: boolean, modelSpecs: PipetteModelSpecs | null,