Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(app): fix estimator update command failure copy during drop tip #16884

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ describe('useDropTipCommandErrors', () => {

act(() => {
result.current({
runCommandError: {
errorType: DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR,
} as any,
type: DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR,
message: 'remove_the_tips_manually',
header: 'cant_safely_drop_tips',
})
})

Expand Down
15 changes: 3 additions & 12 deletions app/src/organisms/DropTipWizardFlows/hooks/errors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import type { RunCommandError } from '@opentrons/shared-data'
import type { ErrorDetails } from '../types'

export interface SetRobotErrorDetailsParams {
runCommandError?: RunCommandError
message?: string
message: string | null
header?: string
type?: RunCommandError['errorType']
}
Expand All @@ -23,16 +22,8 @@ export function useDropTipCommandErrors(
): (cbProps: SetRobotErrorDetailsParams) => void {
const { t } = useTranslation('drop_tip_wizard')

return ({
runCommandError,
message,
header,
type,
}: SetRobotErrorDetailsParams) => {
if (
runCommandError?.errorType ===
DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR
) {
return ({ message, header, type }: SetRobotErrorDetailsParams) => {
if (type === DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR) {
const headerText = t('cant_safely_drop_tips')
const messageText = t('remove_the_tips_manually')

Expand Down
146 changes: 87 additions & 59 deletions app/src/organisms/DropTipWizardFlows/hooks/useDropTipCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { useState, useEffect } from 'react'

import { useDeleteMaintenanceRunMutation } from '@opentrons/react-api-client'

import { DT_ROUTES, MANAGED_PIPETTE_ID } from '../constants'
import {
DROP_TIP_SPECIAL_ERROR_TYPES,
DT_ROUTES,
MANAGED_PIPETTE_ID,
} from '../constants'
import { getAddressableAreaFromConfig } from '../utils'
import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration'
import type {
CreateCommand,
AddressableAreaName,
PipetteModelSpecs,
RunCommandError,
} from '@opentrons/shared-data'
import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data'
import type { CommandData, PipetteData } from '@opentrons/api-client'
Expand Down Expand Up @@ -129,17 +134,25 @@ export function useDropTipCommands({
issuedCommandsType
)

return chainRunCommands(
isFlex
? [
ENGAGE_AXES,
UPDATE_ESTIMATORS_EXCEPT_PLUNGERS,
Z_HOME,
moveToAACommand,
]
: [Z_HOME, moveToAACommand],
false
)
if (isFlex) {
return chainRunCommands(
[ENGAGE_AXES, UPDATE_ESTIMATORS_EXCEPT_PLUNGERS],
false
)
.catch(error => {
// If one of the engage/estimator commands fails, we can safely assume it's because the position is
// unknown, so show the special error modal.
throw {
...error,
errorType: DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR,
}
})
.then(() => {
return chainRunCommands([Z_HOME, moveToAACommand], false)
})
} else {
return chainRunCommands([Z_HOME, moveToAACommand], false)
}
})
.then((commandData: CommandData[]) => {
const error = commandData[0].data.error
Expand All @@ -149,12 +162,12 @@ export function useDropTipCommands({
}
resolve()
})
.catch(error => {
.catch((error: RunCommandError) => {
if (fixitCommandTypeUtils != null && issuedCommandsType === 'fixit') {
fixitCommandTypeUtils.errorOverrides.generalFailure()
} else {
setErrorDetails({
runCommandError: error,
type: error.errorType ?? null,
message: error.detail
? `Error moving to position: ${error.detail}`
: 'Error moving to position: invalid addressable area.',
Expand Down Expand Up @@ -224,51 +237,70 @@ export function useDropTipCommands({
proceed: () => void
): Promise<void> => {
return new Promise((resolve, reject) => {
chainRunCommands(
currentRoute === DT_ROUTES.BLOWOUT
? buildBlowoutCommands(instrumentModelSpecs, isFlex, pipetteId)
: buildDropTipInPlaceCommand(isFlex, pipetteId),
false
)
.then((commandData: CommandData[]) => {
const error = commandData[0].data.error
if (error != null) {
if (
fixitCommandTypeUtils != null &&
issuedCommandsType === 'fixit'
) {
if (currentRoute === DT_ROUTES.BLOWOUT) {
fixitCommandTypeUtils.errorOverrides.blowoutFailed()
} else {
fixitCommandTypeUtils.errorOverrides.tipDropFailed()
}
}

setErrorDetails({
runCommandError: error,
message: `Error moving to position: ${error.detail}`,
})
} else {
proceed()
resolve()
}
})
.catch((error: Error) => {
if (fixitCommandTypeUtils != null && issuedCommandsType === 'fixit') {
if (currentRoute === DT_ROUTES.BLOWOUT) {
fixitCommandTypeUtils.errorOverrides.blowoutFailed()
} else {
fixitCommandTypeUtils.errorOverrides.tipDropFailed()
}
}
const isBlowoutRoute = currentRoute === DT_ROUTES.BLOWOUT

const handleError = (error: RunCommandError | Error): void => {
if (fixitCommandTypeUtils != null && issuedCommandsType === 'fixit') {
isBlowoutRoute
? fixitCommandTypeUtils.errorOverrides.blowoutFailed()
: fixitCommandTypeUtils.errorOverrides.tipDropFailed()
} else {
const operation = isBlowoutRoute ? 'blowout' : 'drop tip'
const type = 'errorType' in error ? error.errorType : undefined
const messageDetail =
'message' in error ? error.message : error.detail

setErrorDetails({
message: `Error issuing ${
currentRoute === DT_ROUTES.BLOWOUT ? 'blowout' : 'drop tip'
} command: ${error.message}`,
type,
message:
messageDetail != null
? `Error during ${operation}: ${messageDetail}`
: null,
})
resolve()
}
reject(error)
}

// Throw any errors in the response body if any.
const handleSuccess = (commandData: CommandData[]): void => {
const error = commandData[0].data.error
if (error != null) {
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw error
}
proceed()
resolve()
}

// For Flex, we need extra preparation steps
const prepareFlexBlowout = (): Promise<CommandData[]> => {
return chainRunCommands(
[ENGAGE_AXES, UPDATE_PLUNGER_ESTIMATORS],
false
).catch(error => {
throw {
...error,
errorType: DROP_TIP_SPECIAL_ERROR_TYPES.MUST_HOME_ERROR,
}
})
}

const executeCommands = (): Promise<CommandData[]> => {
const commands = isBlowoutRoute
? buildBlowoutCommands(instrumentModelSpecs, isFlex, pipetteId)
: buildDropTipInPlaceCommand(isFlex, pipetteId)

return chainRunCommands(commands, false)
}

if (isBlowoutRoute && isFlex) {
prepareFlexBlowout()
.then(executeCommands)
.then(handleSuccess)
.catch(handleError)
} else {
executeCommands().then(handleSuccess).catch(handleError)
}
})
}

Expand Down Expand Up @@ -356,13 +388,10 @@ const buildBlowoutCommands = (
): CreateCommand[] =>
isFlex
? [
ENGAGE_AXES,
UPDATE_PLUNGER_ESTIMATORS,
{
commandType: 'unsafe/blowOutInPlace',
params: {
pipetteId: pipetteId ?? MANAGED_PIPETTE_ID,

flowRate: Math.min(
specs.defaultBlowOutFlowRate.value,
MAXIMUM_BLOWOUT_FLOW_RATE_UL_PER_S
Expand All @@ -376,7 +405,6 @@ const buildBlowoutCommands = (
commandType: 'blowOutInPlace',
params: {
pipetteId: pipetteId ?? MANAGED_PIPETTE_ID,

flowRate: specs.defaultBlowOutFlowRate.value,
},
},
Expand Down
Loading