Skip to content

Commit

Permalink
feat(app): Add Drop Tip Flows to Error Recovery (#15379)
Browse files Browse the repository at this point in the history
Closes EXEC-466

Wires up Drop Tip Flows to Error Recovery through the "Cancel Run" option when tips are detected.
  • Loading branch information
mjhuff authored Jun 11, 2024
1 parent 10cbe02 commit 51dd2bd
Show file tree
Hide file tree
Showing 55 changed files with 1,307 additions and 290 deletions.
2 changes: 0 additions & 2 deletions app/src/assets/localization/en/drop_tip_wizard.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
"go_back": "go back",
"move_to_slot": "move to slot",
"no_proceed_to_drop_tip": "No, proceed to tip removal",
"proceed_to_cancel": "Proceed to cancel",
"proceed_to_tip_selection": "Proceed to tip selection",
"position_and_blowout": "Ensure that the pipette tip is centered above and level with where you want the liquid to be blown out. If it isn't, use the controls below or your keyboard to jog the pipette until it is properly aligned.",
"position_and_drop_tip": "Ensure that the pipette tip is centered above and level with where you want to drop the tips. If it isn't, use the controls below or your keyboard to jog the pipette until it is properly aligned.",
"position_the_pipette": "position the pipette",
Expand Down
10 changes: 8 additions & 2 deletions app/src/assets/localization/en/error_recovery.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@
"are_you_sure_you_want_to_cancel": "Are you sure you want to cancel?",
"are_you_sure_you_want_to_resume": "Are you sure you want to resume?",
"before_you_begin": "Before you begin",
"begin_removal": "Begin removal",
"cancel_run": "Cancel run",
"canceling_run": "Canceling run",
"choose_a_recovery_action": "Choose a recovery action",
"confirm": "Confirm",
"continue": "Continue",
"general_error": "General error",
"general_error_message": "<Placeholder>",
"go_back": "Go back",
"how_do_you_want_to_proceed": "How do you want to proceed?",
"launch_recovery_mode": "Launch Recovery Mode",
"proceed_to_cancel": "Proceed to cancel",
"proceed_to_tip_selection": "Proceed to tip selection",
"recovery_mode": "Recovery Mode",
"recovery_mode_explanation": "<block>Recovery Mode provides you with guided and manual controls for handling errors at runtime.</block><br/><block>You can make changes to ensure the step in progress when the error occurred can be completed or choose to cancel the protocol. When changes are made and no subsequent errors are detected, the method completes. Depending on the conditions that caused the error, you will only be provided with appropriate options.</block>",
"retry_step": "Retry step",
"run_paused": "Run paused",
"run_will_resume": "The run will resume from the point at which the error occurred. Take any necessary actions to correct the problem first. If the step is completed successfully, the protocol continues.",
"if_tips_are_attached": "If tips are attached, you can choose to blow out any aspirated liquid and drop tips before the run is terminated.",
"preserve_aspirated_liquid": "First, do you need to preserve aspirated liquid?",
"skip": "Skip",
"stand_back": "Stand back, robot is in motion",
"stand_back_resuming": "Stand back, resuming current step",
"stand_back_retrying": "Stand back, retrying current command",
"tip_not_detected": "Tip not detected",
"view_error_details": "View error details",
"view_recovery_options": "View recovery options"
"view_recovery_options": "View recovery options",
"you_may_want_to_remove": "You may want to remove the tips from the {{mount}} pipette before using it again in a protocol"
}
59 changes: 30 additions & 29 deletions app/src/organisms/DropTipWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,14 @@ import { DT_ROUTES } from './constants'
import blowoutVideo from '../../assets/videos/droptip-wizard/Blowout-Liquid.webm'
import droptipVideo from '../../assets/videos/droptip-wizard/Drop-tip.webm'

import type { UseDropTipRoutingResult } from './hooks'

interface BeforeBeginningProps {
isOnDevice: boolean
proceedToRoute: UseDropTipRoutingResult['proceedToRoute']
}

export const BeforeBeginning = (
props: BeforeBeginningProps
): JSX.Element | null => {
const { proceedToRoute, isOnDevice } = props
import type { DropTipWizardContainerProps } from './types'

export const BeforeBeginning = ({
proceedToRoute,
isOnDevice,
issuedCommandsType,
fixitCommandTypeUtils,
}: DropTipWizardContainerProps): JSX.Element | null => {
const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared'])
const [flowType, setFlowType] = React.useState<
'blowout' | 'drop_tips' | null
Expand All @@ -52,18 +49,20 @@ export const BeforeBeginning = (
}
}

const buildTopText = (): string => {
if (issuedCommandsType === 'fixit') {
return fixitCommandTypeUtils?.copyOverrides
.tipDropCompleteBtnCopy as string
} else {
return t('before_you_begin_do_you_want_to_blowout')
}
}

if (isOnDevice) {
return (
<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
height="100%"
>
<Flex flexDirection={DIRECTION_COLUMN}>
<Flex css={ODD_TITLE_STYLE}>
{t('before_you_begin_do_you_want_to_blowout')}
</Flex>
<>
<Flex flexDirection={DIRECTION_COLUMN} height="100%">
<Flex css={ODD_TITLE_STYLE}>{buildTopText()}</Flex>
<Flex paddingBottom={SPACING.spacing8}>
<MediumButton
buttonType={flowType === 'blowout' ? 'primary' : 'secondary'}
Expand All @@ -74,6 +73,7 @@ export const BeforeBeginning = (
buttonText={i18n.format(t('yes_blow_out_liquid'), 'capitalize')}
justifyContent={JUSTIFY_FLEX_START}
paddingLeft={SPACING.spacing24}
height="5.25rem"
/>
</Flex>
<Flex>
Expand All @@ -89,17 +89,18 @@ export const BeforeBeginning = (
)}
justifyContent={JUSTIFY_FLEX_START}
paddingLeft={SPACING.spacing24}
height="5.25rem"
/>
</Flex>
<Flex justifyContent={JUSTIFY_FLEX_END} marginTop="auto">
<SmallButton
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
onClick={handleProceed}
disabled={flowType == null}
/>
</Flex>
</Flex>
<Flex justifyContent={JUSTIFY_FLEX_END}>
<SmallButton
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
onClick={handleProceed}
disabled={flowType == null}
/>
</Flex>
</Flex>
</>
)
} else {
return (
Expand Down
23 changes: 7 additions & 16 deletions app/src/organisms/DropTipWizardFlows/ChooseLocation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,17 @@ import { getDeckDefFromRobotType } from '@opentrons/shared-data'
import { SmallButton } from '../../atoms/buttons'
import { TwoUpTileLayout } from '../LabwarePositionCheck/TwoUpTileLayout'

import type { AddressableAreaName, RobotType } from '@opentrons/shared-data'
import type { AddressableAreaName } from '@opentrons/shared-data'
import type { DropTipWizardContainerProps } from './types'

// TODO: get help link article URL

interface ChooseLocationProps {
type ChooseLocationProps = DropTipWizardContainerProps & {
handleProceed: () => void
handleGoBack: () => void
title: string
body: string | JSX.Element
robotType: RobotType
moveToAddressableArea: (addressableArea: AddressableAreaName) => Promise<void>
isOnDevice: boolean
}

export const ChooseLocation = (
Expand Down Expand Up @@ -70,17 +69,8 @@ export const ChooseLocation = (

if (isOnDevice) {
return (
<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
flex="1"
>
<Flex
flexDirection={DIRECTION_ROW}
gridGap={SPACING.spacing24}
flex="1"
>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing32}>
<Flex flexDirection={DIRECTION_ROW} flex="1">
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing8}
Expand All @@ -105,6 +95,7 @@ export const ChooseLocation = (
justifyContent={JUSTIFY_SPACE_BETWEEN}
css={ALIGN_BUTTONS}
gridGap={SPACING.spacing8}
marginTop="auto"
>
<Btn
onClick={() => {
Expand Down Expand Up @@ -174,7 +165,7 @@ const GO_BACK_BUTTON_STYLE = css`
@media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} {
font-weight: ${TYPOGRAPHY.fontWeightSemiBold};
font-size: ${TYPOGRAPHY.fontSize22};
padding-left: 0rem;
padding-left: 0;
&:hover {
opacity: 100%;
}
Expand Down
51 changes: 39 additions & 12 deletions app/src/organisms/DropTipWizardFlows/DropTipWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
DIRECTION_COLUMN,
Flex,
JUSTIFY_FLEX_END,
JUSTIFY_SPACE_BETWEEN,
POSITION_ABSOLUTE,
SPACING,
StyledText,
useConditionalConfirm,
} from '@opentrons/components'
Expand Down Expand Up @@ -50,7 +52,6 @@ export type DropTipWizardProps = DropTipWizardFlowsProps &
export function DropTipWizard(props: DropTipWizardProps): JSX.Element {
const {
issuedCommandsType,
fixitCommandTypeUtils,
activeMaintenanceRunId,
proceed,
goBack,
Expand Down Expand Up @@ -86,11 +87,7 @@ export function DropTipWizard(props: DropTipWizardProps): JSX.Element {
// Either proceed to drop tip if blowout or execute the close flow routine, accounting for the commands type.
const proceedWithConditionalClose = (): Promise<void> => {
if (isFinalWizardStep) {
if (fixitCommandTypeUtils != null) {
return fixitCommandTypeUtils.onCloseFlow()
} else {
return dropTipCommands.handleCleanUpAndClose()
}
return dropTipCommands.handleCleanUpAndClose()
} else {
return proceed()
}
Expand All @@ -112,6 +109,7 @@ export function DropTipWizard(props: DropTipWizardProps): JSX.Element {
)
}

// TODO(jh, 06-07-24): All content views could use refactoring and DQA. Create shared components from designs. EXEC-520.
export function DropTipWizardContainer(
props: DropTipWizardContainerProps
): JSX.Element {
Expand All @@ -137,6 +135,20 @@ export function DropTipWizardFixitType(
export function DropTipWizardSetupType(
props: DropTipWizardContainerProps
): JSX.Element {
const {
activeMaintenanceRunId,
isCommandInProgress,
isExiting,
showConfirmExit,
errorDetails,
} = props

// TODO(jh: 06-10-24): This is not ideal. See EXEC-520.
const inMotion =
isCommandInProgress || isExiting || activeMaintenanceRunId == null
const simpleWizardPaddingOverrides =
inMotion || showConfirmExit || errorDetails

return createPortal(
props.isOnDevice ? (
<Flex
Expand All @@ -152,7 +164,15 @@ export function DropTipWizardSetupType(
backgroundColor={COLORS.white}
>
<DropTipWizardHeader {...props} />
<DropTipWizardContent {...props} />
<Flex
padding={simpleWizardPaddingOverrides ? 0 : SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
height="100%"
flex="1"
>
<DropTipWizardContent {...props} />
</Flex>
</Flex>
) : (
<LegacyModalShell
Expand All @@ -177,6 +197,7 @@ export const DropTipWizardContent = (
errorDetails,
isCommandInProgress,
fixitCommandTypeUtils,
issuedCommandsType,
isExiting,
proceed,
proceedToRoute,
Expand All @@ -203,6 +224,7 @@ export const DropTipWizardContent = (
function buildShowExitConfirmation(): JSX.Element {
return (
<ExitConfirmation
{...props}
handleGoBack={cancelExit}
handleExit={() => {
toggleExitInitiated()
Expand All @@ -222,6 +244,7 @@ export const DropTipWizardContent = (
header={errorDetails?.header ?? t('error_dropping_tips')}
subHeader={subHeader}
justifyContentForOddButton={JUSTIFY_FLEX_END}
marginTop={`-${SPACING.spacing68}`} // See EXEC-520. This clearly isn't ideal.
>
{button}
</SimpleWizardBody>
Expand Down Expand Up @@ -297,10 +320,8 @@ export const DropTipWizardContent = (
}

const buildProceedText = (): string => {
if (fixitCommandTypeUtils != null) {
const btnText = fixitCommandTypeUtils.copyOverrides.tipDropCompleteBtn

return t(`drop_tip_wizard::${btnText}`)
if (fixitCommandTypeUtils != null && currentStep === DROP_TIP_SUCCESS) {
return fixitCommandTypeUtils.copyOverrides.tipDropCompleteBtnCopy
} else {
return currentStep === BLOWOUT_SUCCESS
? i18n.format(t('shared:continue'), 'capitalize')
Expand All @@ -323,7 +344,13 @@ export const DropTipWizardContent = (
}

function buildModalContent(): JSX.Element {
if (activeMaintenanceRunId == null) {
// Don't render the spinner screen for 1 render cycle on fixit commands.
if (currentStep === BEFORE_BEGINNING && issuedCommandsType === 'fixit') {
return buildBeforeBeginning()
} else if (
activeMaintenanceRunId == null &&
issuedCommandsType === 'setup'
) {
return buildGettingReady()
} else if (isCommandInProgress || isExiting) {
return buildRobotInMotion()
Expand Down
6 changes: 5 additions & 1 deletion app/src/organisms/DropTipWizardFlows/ExitConfirmation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react'
import { useSelector } from 'react-redux'
import { useTranslation } from 'react-i18next'

import {
Flex,
COLORS,
Expand All @@ -9,11 +10,14 @@ import {
SecondaryButton,
JUSTIFY_FLEX_END,
} from '@opentrons/components'

import { getIsOnDevice } from '../../redux/config'
import { SimpleWizardBody } from '../../molecules/SimpleWizardBody'
import { SmallButton } from '../../atoms/buttons'

interface ExitConfirmationProps {
import type { DropTipWizardContainerProps } from './types'

type ExitConfirmationProps = DropTipWizardContainerProps & {
handleExit: () => void
handleGoBack: () => void
}
Expand Down
Loading

0 comments on commit 51dd2bd

Please sign in to comment.