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

feat(app): add desktop and ODD droptip wizard loading/confirmation/errors on app #13815

Merged
merged 13 commits into from
Oct 25, 2023
Merged
13 changes: 13 additions & 0 deletions app/src/assets/localization/en/drop_tip_wizard.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
{
"before_you_begin_do_you_want_to_blowout": "Before you begin, do you need to preserve aspirated liquid?",
"blowout_liquid": "Blow out liquid",
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
"blowout_complete": "blowout complete",
"choose_blowout_location": "choose blowout location",
"choose_drop_tip_location": "choose tip-drop location",
"confirm_blowout_location": "Is the pipette positioned where the liquids should be blown out?",
"confirm_drop_tip_location": "Is the pipette positioned where the tips should be dropped?",
"drop_tips": "drop tips",
"drop_tip_complete": "tip drop complete",
"drop_tip_failed": "The drop tip could not be completed. Contact customer support for assistance.",
"error_dropping_tips": "Error dropping tips",
"exit_screen_title": "Exit before completing drop tip?",
"go_back": "go back",
"move_to_slot": "move to slot",
"no_proceed_to_drop_tip": "No, proceed to tip removal",
"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",
"select_blowout_slot": "<block>You can blow out liquid into a labware or dispose of it.</block><block>Select the slot where you want to blow out the liquid on the deck map to the right. Once confirmed, the gantry will move to the chosen slot.</block>",
"select_blowout_slot_odd": "<block>You can blow out liquid into a labware or dispose of it.</block><block>After the gantry moves to the chosen slot, use the jog controls to move the pipette to the exact position for blowing out.</block>",
"select_drop_tip_slot": "<block>You can return tips to a tip rack or dispose of them.</block><block>Select the slot where you want to drop the tips on the deck map to the right. Once confirmed, the gantry will move to the chosen slot.</block>",
"select_drop_tip_slot_odd": "<block>You can blow out liquid into a labware or dispose of it.</block><block>After the gantry moves to the chosen slot, use the jog controls to move the pipette to the exact position for dropping tips.</block>",
"stand_back_blowing_out": "Stand back, robot is blowing out",
"stand_back_dropping_tips": "Stand back, robot is dropping tips",
"stand_back_exiting": "Stand back, robot is in motion",
"yes_blow_out_liquid": "Yes, blow out liquid in labware"
}
Binary file not shown.
Binary file not shown.
120 changes: 99 additions & 21 deletions app/src/organisms/DropTipWizard/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,113 @@
DISPLAY_INLINE_BLOCK,
JUSTIFY_SPACE_BETWEEN,
PrimaryButton,
JUSTIFY_FLEX_END,
POSITION_ABSOLUTE,
} from '@opentrons/components'
import { StyledText } from '../../atoms/text'
import { NeedHelpLink } from '../CalibrationPanels'
import { SmallButton, MediumButton } from '../../atoms/buttons'
// import { NeedHelpLink } from '../CalibrationPanels'

import blowoutVideo from '../../assets/videos/droptip-wizard/Blowout-Liquid.webm'
import droptipVideo from '../../assets/videos/droptip-wizard/Drop-tip.webm'

// TODO: get help link article URL
const NEED_HELP_URL = ''
// const NEED_HELP_URL = ''

interface BeforeBeginningProps {
handleCreateAndSetup: (shouldDispenseLiquid: boolean) => void
isCreateLoading: boolean
isOnDevice: boolean
}

export const BeforeBeginning = (
props: BeforeBeginningProps
): JSX.Element | null => {
const { handleCreateAndSetup, isCreateLoading } = props
const { handleCreateAndSetup, isCreateLoading, isOnDevice } = props

Check warning on line 41 in app/src/organisms/DropTipWizard/BeforeBeginning.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/BeforeBeginning.tsx#L41

Added line #L41 was not covered by tests
const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared'])
const [flowType, setFlowType] = React.useState<
'liquid_and_tips' | 'only_tips'
>('liquid_and_tips')
'liquid_and_tips' | 'only_tips' | null
>(null)
const handleProceed = (): void => {
handleCreateAndSetup(flowType === 'liquid_and_tips')
}

return (
return isOnDevice ? (
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason we aren't making use of GenericWizardTile here and in the other steps? I notice that these wizard steps have way more styling than step components in other flows (pipette, gripper, etc.). Maybe I'm missing something?

If this is something that actually needs refactoring but is time intensive, we can clean it up later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely overlooked the GenericWizardTile and was styling from scratch. I will refactor to make use of GenericWizardTile

<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
height="100%"
>
<Flex flexDirection={DIRECTION_COLUMN}>
<Flex css={TitleODD}>
{t('before_you_begin_do_you_want_to_blowout')}
</Flex>
<Flex paddingBottom={SPACING.spacing8}>
<MediumButton
buttonType={
flowType === 'liquid_and_tips' ? 'primary' : 'secondary'
}
flex="1"
onClick={() => setFlowType('liquid_and_tips')}

Check warning on line 67 in app/src/organisms/DropTipWizard/BeforeBeginning.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/BeforeBeginning.tsx#L67

Added line #L67 was not covered by tests
buttonText={i18n.format(t('yes_blow_out_liquid'), 'capitalize')}
justifyContent={JUSTIFY_FLEX_START}
paddingLeft={SPACING.spacing24}
/>
</Flex>
<Flex>
<MediumButton
buttonType={flowType === 'only_tips' ? 'primary' : 'secondary'}
flex="1"
onClick={() => {
setFlowType('only_tips')

Check warning on line 78 in app/src/organisms/DropTipWizard/BeforeBeginning.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/BeforeBeginning.tsx#L78

Added line #L78 was not covered by tests
}}
buttonText={i18n.format(t('no_proceed_to_drop_tip'), 'capitalize')}
justifyContent={JUSTIFY_FLEX_START}
paddingLeft={SPACING.spacing24}
/>
</Flex>
</Flex>
<Flex justifyContent={JUSTIFY_FLEX_END}>
<SmallButton
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
onClick={handleProceed}
disabled={isCreateLoading || flowType == null}
/>
</Flex>
</Flex>
) : (
<Flex css={TILE_CONTAINER_STYLE}>
<Title>{t('before_you_begin_do_you_want_to_blowout')}</Title>
<Flex flexDirection={DIRECTION_ROW} gridGap={SPACING.spacing24}>
<Flex
flex="1 0 auto"
onClick={() => setFlowType('liquid_and_tips')}
onClick={() => {
setFlowType('liquid_and_tips')

Check warning on line 101 in app/src/organisms/DropTipWizard/BeforeBeginning.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/BeforeBeginning.tsx#L101

Added line #L101 was not covered by tests
}}
css={
flowType === 'liquid_and_tips'
? SELECTED_OPTIONS_STYLE
: UNSELECTED_OPTIONS_STYLE
}
>
{/* <img
src={}
css={css`max-width: 11rem;`}
/> */}
<Flex
height="100%"
width="100%"
position={POSITION_ABSOLUTE}
flex="1"
/>
<video
css={css`
max-width: 11rem;
`}
autoPlay={true}
loop={true}
controls={false}
aria-label="blowout"
>
<source src={blowoutVideo} />
</video>
<StyledText as="h3">{t('yes_blow_out_liquid')}</StyledText>
</Flex>
<Flex
Expand All @@ -68,19 +134,26 @@
: UNSELECTED_OPTIONS_STYLE
}
>
{/* <img
src={}
css={css`max-width: 11rem;`}
/> */}
<video
css={css`
max-width: 11rem;
`}
autoPlay={true}
loop={true}
controls={false}
aria-label="droptip"
>
<source src={droptipVideo} />
</video>
<StyledText as="h3">{t('no_proceed_to_drop_tip')}</StyledText>
</Flex>
</Flex>
<Flex
flexDirection={DIRECTION_ROW}
justifyContent={JUSTIFY_SPACE_BETWEEN}
>
<NeedHelpLink href={NEED_HELP_URL} />
<PrimaryButton disabled={isCreateLoading} onClick={handleProceed}>
<Flex flexDirection={DIRECTION_ROW} justifyContent={JUSTIFY_FLEX_END}>
{/* <NeedHelpLink href={NEED_HELP_URL} /> */}
<PrimaryButton
disabled={isCreateLoading || flowType == null}
onClick={handleProceed}
>
{i18n.format(t('shared:continue'), 'capitalize')}
</PrimaryButton>
</Flex>
Expand Down Expand Up @@ -152,6 +225,11 @@
}
`

const TitleODD = css`
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
${TYPOGRAPHY.level4HeaderSemiBold}
margin-bottom: ${SPACING.spacing16};
`

const TILE_CONTAINER_STYLE = css`
flex-direction: ${DIRECTION_COLUMN};
justify-content: ${JUSTIFY_SPACE_BETWEEN};
Expand Down
86 changes: 71 additions & 15 deletions app/src/organisms/DropTipWizard/ChooseLocation.tsx
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,51 @@
Flex,
DIRECTION_COLUMN,
DIRECTION_ROW,
ALIGN_CENTER,
RESPONSIVENESS,
JUSTIFY_SPACE_BETWEEN,
JUSTIFY_CENTER,
JUSTIFY_FLEX_END,
PrimaryButton,
useDeckLocationSelect,
SPACING,
TYPOGRAPHY,
} from '@opentrons/components'
import { NeedHelpLink } from '../CalibrationPanels'
import { StyledText } from '../../atoms/text'
// import { NeedHelpLink } from '../CalibrationPanels'
import { TwoUpTileLayout } from '../LabwarePositionCheck/TwoUpTileLayout'
import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal'
import { RobotType, getDeckDefFromRobotType } from '@opentrons/shared-data'
import type { CommandData } from '@opentrons/api-client'
import { SmallButton } from '../../atoms/buttons'

// TODO: get help link article URL
const NEED_HELP_URL = ''
// const NEED_HELP_URL = ''

interface ChooseLocationProps {
handleProceed: () => void
title: string
body: string | JSX.Element
robotType: RobotType
moveToXYCoordinate: (x: number, y: number) => Promise<void>
moveToXYCoordinate: (x: number, y: number) => Promise<CommandData[] | null>
isRobotMoving: boolean
isOnDevice: boolean
setErrorMessage: (arg0: string) => void
}

export const ChooseLocation = (
props: ChooseLocationProps
): JSX.Element | null => {
const { handleProceed, title, body, robotType, moveToXYCoordinate } = props
const { t } = useTranslation(['drop_tip_wizard', 'shared'])
const {
handleProceed,
title,
body,
robotType,
moveToXYCoordinate,
isRobotMoving,
isOnDevice,
setErrorMessage,
} = props
const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared'])

Check warning on line 52 in app/src/organisms/DropTipWizard/ChooseLocation.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/ChooseLocation.tsx#L51-L52

Added lines #L51 - L52 were not covered by tests
const deckDef = getDeckDefFromRobotType(robotType)
const { DeckLocationSelect, selectedLocation } = useDeckLocationSelect(
robotType
Expand Down Expand Up @@ -58,24 +77,61 @@
targetX,
targetY
)
moveToXYCoordinate(targetX, targetY).then(handleProceed)
moveToXYCoordinate(targetX, targetY)
.then(() => handleProceed())
.catch(e => setErrorMessage(`${e.message}`))

Check warning on line 82 in app/src/organisms/DropTipWizard/ChooseLocation.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/ChooseLocation.tsx#L80-L82

Added lines #L80 - L82 were not covered by tests
}
}
return (

if (isRobotMoving) {
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
return (

Check warning on line 87 in app/src/organisms/DropTipWizard/ChooseLocation.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/organisms/DropTipWizard/ChooseLocation.tsx#L87

Added line #L87 was not covered by tests
<InProgressModal
alternativeSpinner={null}
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
description={t('stand_back_exiting')}
/>
)
}

return isOnDevice ? (
<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
>
<Flex flexDirection={DIRECTION_ROW} gridGap={SPACING.spacing48} flex="1">
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing8}
width="100%"
flex="1"
>
<StyledText as="h4" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{title}
</StyledText>
<StyledText as="p">{body}</StyledText>
</Flex>
<Flex flex="1" justifyContent={JUSTIFY_CENTER}>
{DeckLocationSelect}
</Flex>
</Flex>
<Flex justifyContent={JUSTIFY_FLEX_END}>
<SmallButton
buttonText={i18n.format(t('move_to_slot'), 'capitalize')}
onClick={handleConfirmPosition}
/>
</Flex>
</Flex>
) : (
<Flex css={TILE_CONTAINER_STYLE}>
<TwoUpTileLayout
title={title}
body={body}
rightElement={DeckLocationSelect}
footer={
<Flex
flexDirection={DIRECTION_ROW}
justifyContent={JUSTIFY_SPACE_BETWEEN}
alignItems={ALIGN_CENTER}
>
<NeedHelpLink href={NEED_HELP_URL} />
<Flex flexDirection={DIRECTION_ROW} justifyContent={JUSTIFY_FLEX_END}>
{/* <NeedHelpLink href={NEED_HELP_URL} /> */}
<PrimaryButton onClick={handleConfirmPosition}>
{t('shared:confirm_position')}
{i18n.format(t('move_to_slot'), 'capitalize')}
</PrimaryButton>
</Flex>
}
Expand Down
17 changes: 7 additions & 10 deletions app/src/organisms/DropTipWizard/ExitConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,15 @@ export function ExitConfirmation(props: ExitConfirmationProps): JSX.Element {
const flowTitle = t('drop_tips')
const isOnDevice = useSelector(getIsOnDevice)

if (isRobotMoving)
return (
<InProgressModal
description={t('shared:stand_back_robot_is_in_motion')}
/>
)

return (
return isRobotMoving ? (
<InProgressModal
alternativeSpinner={null}
ncdiehl11 marked this conversation as resolved.
Show resolved Hide resolved
description={t('stand_back_exiting')}
/>
) : (
<SimpleWizardBody
iconColor={COLORS.warningEnabled}
header={t('progress_will_be_lost', { flow: flowTitle })}
subHeader={t('are_you_sure_exit', { flow: flowTitle })}
header={t('exit_screen_title', { flow: flowTitle })}
isSuccess={false}
>
{isOnDevice ? (
Expand Down
Loading
Loading