From 8eaf08250bea77d66b7ae75307306b94f6ab0f26 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Oct 2023 12:38:07 -0400 Subject: [PATCH 01/13] initial changes before tests --- .../localization/en/drop_tip_wizard.json | 12 + .../DropTipWizard/ChooseLocation.tsx | 22 +- .../DropTipWizard/ExitConfirmation.tsx | 4 +- .../organisms/DropTipWizard/JogToPosition.tsx | 123 +++++++++- app/src/organisms/DropTipWizard/Success.tsx | 24 +- app/src/organisms/DropTipWizard/index.tsx | 211 +++++++++++------- 6 files changed, 299 insertions(+), 97 deletions(-) diff --git a/app/src/assets/localization/en/drop_tip_wizard.json b/app/src/assets/localization/en/drop_tip_wizard.json index afabf944b56..58058a3c447 100644 --- a/app/src/assets/localization/en/drop_tip_wizard.json +++ b/app/src/assets/localization/en/drop_tip_wizard.json @@ -1,15 +1,27 @@ { "before_you_begin_do_you_want_to_blowout": "Before you begin, do you need to preserve aspirated liquid?", + "blowout_liquid": "Blow out liquid", "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", "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": "You can blow out liquid into a labware or dispose of it.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.", + "select_blowout_slot_odd": "You can blow out liquid into a labware or dispose of it.After the gantry moves to the chosen slot, use the jog controls to move the pipette to the exact position for blowing out.", "select_drop_tip_slot": "You can return tips to a tip rack or dispose of them.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.", + "select_drop_tip_slot_odd": "You can blow out liquid into a labware or dispose of it.After the gantry moves to the chosen slot, use the jog controls to move the pipette to the exact position for dropping tips.", + "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" } diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 9c7fe35053e..81ad6af6225 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -13,7 +13,9 @@ import { } from '@opentrons/components' 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' // TODO: get help link article URL const NEED_HELP_URL = '' @@ -23,13 +25,21 @@ interface ChooseLocationProps { title: string body: string | JSX.Element robotType: RobotType - moveToXYCoordinate: (x: number, y: number) => Promise + moveToXYCoordinate: (x: number, y: number) => Promise + isRobotMoving: boolean } export const ChooseLocation = ( props: ChooseLocationProps ): JSX.Element | null => { - const { handleProceed, title, body, robotType, moveToXYCoordinate } = props + const { + handleProceed, + title, + body, + robotType, + moveToXYCoordinate, + isRobotMoving, + } = props const { t } = useTranslation(['drop_tip_wizard', 'shared']) const deckDef = getDeckDefFromRobotType(robotType) const { DeckLocationSelect, selectedLocation } = useDeckLocationSelect( @@ -61,7 +71,13 @@ export const ChooseLocation = ( moveToXYCoordinate(targetX, targetY).then(handleProceed) } } - return ( + + return isRobotMoving ? ( + + ) : ( {isOnDevice ? ( diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index 4e8de316cfe..f030091e179 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import styled, { css } from 'styled-components' import { useTranslation } from 'react-i18next' +import { POSITION_AND_BLOWOUT } from './constants' import { Flex, DIRECTION_COLUMN, @@ -11,16 +12,19 @@ import { SecondaryButton, SPACING, ALIGN_FLEX_START, + JUSTIFY_FLEX_END, TYPOGRAPHY, + COLORS, } from '@opentrons/components' import { NeedHelpLink } from '../CalibrationPanels' -import { useSelector } from 'react-redux' -import { getIsOnDevice } from '../../redux/config' import { SmallButton } from '../../atoms/buttons' import { Jog, JogControls } from '../../molecules/JogControls' import { Portal } from '../../App/portal' import { LegacyModalShell } from '../../molecules/LegacyModal' +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { StyledText } from '../../atoms/text' +import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' +import { PipetteModelSpecs } from '@opentrons/shared-data' // TODO: get help link article URL const NEED_HELP_URL = '' @@ -32,27 +36,124 @@ const Header = styled.h1` } ` +interface ConfirmPositionProps { + handleBlowout: () => void + handleGoBack: () => void + isOnDevice: boolean + currentStep: string +} + +const ConfirmPosition = (props: ConfirmPositionProps): JSX.Element | null => { + const { handleBlowout, handleGoBack, isOnDevice, currentStep } = props + const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) + const flowTitle = t('drop_tips') + + return ( + + {isOnDevice ? ( + + + + + ) : ( + <> + + {t('shared:go_back')} + + + {currentStep === POSITION_AND_BLOWOUT + ? i18n.format(t('blowout_liquid'), 'capitalize') + : i18n.format(t('drop_tips'), 'capitalize')} + + + )} + + ) +} + interface JogToPositionProps { - handleProceed: () => void handleGoBack: () => void handleJog: Jog + handleProceed: () => void body: string + isRobotMoving: boolean + isExiting: boolean + chainRunCommands: any + currentStep: string + createdMaintenanceRunId: string | null + pipetteId: string + instrumentModelSpecs: PipetteModelSpecs + isOnDevice: boolean } export const JogToPosition = ( props: JogToPositionProps ): JSX.Element | null => { - const { handleProceed, handleGoBack, handleJog, body } = props + const { + handleGoBack, + handleJog, + handleProceed, + body, + isRobotMoving, + isExiting, + currentStep, + isOnDevice, + } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) - const isOnDevice = useSelector(getIsOnDevice) const [showFullJogControls, setShowFullJogControls] = React.useState(false) + const [ + showPositionConfirmation, + setShowPositionConfirmation, + ] = React.useState(false) - const handleConfirmPosition = (): void => { - console.log('TODO: handle confirm position and show confirm screen') - handleProceed() + if (showPositionConfirmation) { + return ( + setShowPositionConfirmation(false)} + isOnDevice={isOnDevice} + currentStep={currentStep} + /> + ) } - return ( + return isRobotMoving && !isExiting ? ( + + ) : ( setShowPositionConfirmation(true)} /> @@ -151,7 +252,7 @@ export const JogToPosition = ( {t('shared:go_back')} - + setShowPositionConfirmation(true)}> {t('shared:confirm_position')} diff --git a/app/src/organisms/DropTipWizard/Success.tsx b/app/src/organisms/DropTipWizard/Success.tsx index 8725abd1bd2..3d6c2289aaf 100644 --- a/app/src/organisms/DropTipWizard/Success.tsx +++ b/app/src/organisms/DropTipWizard/Success.tsx @@ -10,19 +10,37 @@ import { } from '@opentrons/components' import { getIsOnDevice } from '../../redux/config' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' +import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { SmallButton } from '../../atoms/buttons' +import { BLOWOUT_SUCCESS } from './constants' interface SuccessProps { message: string proceedText: string handleProceed: () => void + isRobotMoving: boolean + isExiting: boolean + currentStep: string } export const Success = (props: SuccessProps): JSX.Element => { - const { message, proceedText, handleProceed } = props - const { i18n } = useTranslation() + const { + message, + proceedText, + handleProceed, + isRobotMoving, + isExiting, + currentStep, + } = props const isOnDevice = useSelector(getIsOnDevice) - return ( + const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) + + return isRobotMoving && !isExiting ? ( + + ) : ( { console.error(error.message) + setErrorMessage(`error exiting: ${error.message}`) deleteMaintenanceRun(maintenanceRunData?.data.id) setIsExiting(false) props.onComplete?.() @@ -220,9 +223,9 @@ export const DropTipWizardComponent = ( isCreateLoading, isRobotMoving, // createRunCommand, - // setErrorMessage, + setErrorMessage, errorMessage, - // isExiting, + isExiting, createdMaintenanceRunId, instrumentModelSpecs, } = props @@ -267,7 +270,9 @@ export const DropTipWizardComponent = ( true ) .then(data => {}) - .catch((e: Error) => {}) + .catch((e: Error) => + setErrorMessage(`error issuing jog command: ${e.message}`) + ) } } @@ -282,55 +287,53 @@ export const DropTipWizardComponent = ( .then(() => { setShouldDispenseLiquid(shouldDispenseLiquid) }) - .catch(e => e) + .catch(e => + setErrorMessage(`error setting up blowout/droptip: ${e.message}`) + ) } - const retractAllAxesAndSavePosition = (): Promise => { + const retractAllAxesAndSavePosition = (): Promise => { if (createdMaintenanceRunId == null) return Promise.reject( new Error('no maintenance run present to send move commands to') ) - return chainRunCommands( - createdMaintenanceRunId, - [ - { - commandType: 'retractAxis' as const, - params: { - axis: 'leftZ', - }, - }, - { - commandType: 'retractAxis' as const, - params: { - axis: 'rightZ', - }, - }, - { - commandType: 'retractAxis' as const, - params: { axis: 'x' }, + const commands: CreateCommand[] = [ + { + commandType: 'retractAxis' as const, + params: { + axis: 'leftZ', }, - { - commandType: 'retractAxis' as const, - params: { axis: 'y' }, + }, + { + commandType: 'retractAxis' as const, + params: { + axis: 'rightZ', }, - { - commandType: 'savePosition' as const, - params: { - pipetteId: MANAGED_PIPETTE_ID, - }, + }, + { + commandType: 'retractAxis' as const, + params: { axis: 'x' }, + }, + { + commandType: 'retractAxis' as const, + params: { axis: 'y' }, + }, + { + commandType: 'savePosition' as const, + params: { + pipetteId: MANAGED_PIPETTE_ID, }, - ], - true - ).then( - ([ - _retract1Response, - _retract2Response, - _retract3Response, - _retract4Response, - savePositionResponse, - ]) => { - const currentPosition = (savePositionResponse.data as SavePositionRunTimeCommand) - .result?.position + }, + ] + return chainRunCommands(createdMaintenanceRunId, commands, false) + .then(responses => { + if (responses.length !== commands.length) { + return Promise.reject( + new Error('not all commands executed successfully') + ) + } + const currentPosition = (responses[responses.length - 1] + .data as SavePositionRunTimeCommand).result?.position if (currentPosition != null) { return Promise.resolve(currentPosition) } else { @@ -338,8 +341,12 @@ export const DropTipWizardComponent = ( new Error('current position could not be saved') ) } - } - ) + }) + .catch(e => + setErrorMessage( + `error retracting x and y axes or saving position: ${e.message}` + ) + ) } const moveToXYCoordinate = (x: number, y: number): Promise => { @@ -349,31 +356,33 @@ export const DropTipWizardComponent = ( ) return retractAllAxesAndSavePosition() - .then(currentPosition => - chainRunCommands( - createdMaintenanceRunId, - [ - { - commandType: 'moveRelative', - params: { - pipetteId: MANAGED_PIPETTE_ID, - distance: y - currentPosition.y, - axis: 'y', + .then(currentPosition => { + if (currentPosition != null) { + chainRunCommands( + createdMaintenanceRunId, + [ + { + commandType: 'moveRelative', + params: { + pipetteId: MANAGED_PIPETTE_ID, + distance: y - currentPosition.y, + axis: 'y', + }, }, - }, - { - commandType: 'moveRelative', - params: { - pipetteId: MANAGED_PIPETTE_ID, - distance: x - currentPosition.x, - axis: 'x', + { + commandType: 'moveRelative', + params: { + pipetteId: MANAGED_PIPETTE_ID, + distance: x - currentPosition.x, + axis: 'x', + }, }, - }, - ], - true - ) - ) - .catch(e => e) + ], + true + ) + } + }) + .catch(e => setErrorMessage(`error moving to position: ${e.message}`)) } let modalContent: JSX.Element =
UNASSIGNED STEP
@@ -385,9 +394,28 @@ export const DropTipWizardComponent = ( isRobotMoving={isRobotMoving} /> ) + } else if (errorMessage != null) { + modalContent = ( + + {t('drop_tip_failed')} + {errorMessage} + + } + /> + ) } else if (shouldDispenseLiquid == null) { modalContent = ( - + ) } else if ( currentStep === CHOOSE_BLOWOUT_LOCATION || @@ -399,21 +427,26 @@ export const DropTipWizardComponent = ( handleProceed={proceed} title={ currentStep === CHOOSE_BLOWOUT_LOCATION - ? t('choose_blowout_location') - : t('choose_drop_tip_location') + ? i18n.format(t('choose_blowout_location'), 'capitalize') + : i18n.format(t('choose_drop_tip_location'), 'capitalize') } body={ }} /> } moveToXYCoordinate={moveToXYCoordinate} + isRobotMoving={isRobotMoving} /> ) } else if ( @@ -446,17 +479,36 @@ export const DropTipWizardComponent = ( ) .then(() => { retractAllAxesAndSavePosition() + .then(() => proceed()) + .catch(e => + setErrorMessage(`error moving to position: ${e.message}`) + ) }) - .catch(e => e) - proceed() + .catch(e => + setErrorMessage( + `error issuing ${ + currentStep === POSITION_AND_BLOWOUT + ? 'blowout' + : 'drop tip' + } command: ${e.message}` + ) + ) } }} + isRobotMoving={isRobotMoving} + isExiting={isExiting} handleGoBack={goBack} body={ currentStep === POSITION_AND_BLOWOUT ? t('position_and_blowout') : t('position_and_drop_tip') } + createdMaintenanceRunId={createdMaintenanceRunId} + pipetteId={MANAGED_PIPETTE_ID} + instrumentModelSpecs={instrumentModelSpecs} + chainRunCommands={chainRunCommands} + currentStep={currentStep} + isOnDevice={isOnDevice} /> ) } else if ( @@ -475,9 +527,12 @@ export const DropTipWizardComponent = ( } proceedText={ currentStep === BLOWOUT_SUCCESS - ? t('shared:continue') - : t('shared:exit') + ? i18n.format(t('shared:continue'), 'capitalize') + : i18n.format(t('shared:exit'), 'capitalize') } + isRobotMoving={isRobotMoving} + isExiting={isExiting} + currentStep={currentStep} /> ) } From 679b95812851008a5806e4e3a8c25ef62e728621 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 17 Oct 2023 12:50:32 -0400 Subject: [PATCH 02/13] update robot in motion logic for jogtoposition component --- .../DropTipWizard/ChooseLocation.tsx | 2 +- .../organisms/DropTipWizard/JogToPosition.tsx | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 81ad6af6225..33632801bec 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -68,7 +68,7 @@ export const ChooseLocation = ( targetX, targetY ) - moveToXYCoordinate(targetX, targetY).then(handleProceed) + moveToXYCoordinate(targetX, targetY).then(() => handleProceed()) } } diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index f030091e179..8a1358e3f49 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -134,7 +134,16 @@ export const JogToPosition = ( ] = React.useState(false) if (showPositionConfirmation) { - return ( + return isRobotMoving ? ( + + ) : ( setShowPositionConfirmation(false)} @@ -143,17 +152,7 @@ export const JogToPosition = ( /> ) } - - return isRobotMoving && !isExiting ? ( - - ) : ( + return ( Date: Tue, 17 Oct 2023 16:00:56 -0400 Subject: [PATCH 03/13] fix movement loading states --- .../DropTipWizard/ChooseLocation.tsx | 5 +- .../DropTipWizard/ExitConfirmation.tsx | 14 ++-- .../organisms/DropTipWizard/JogToPosition.tsx | 37 +++++---- app/src/organisms/DropTipWizard/Success.tsx | 3 - app/src/organisms/DropTipWizard/index.tsx | 80 +++++++------------ 5 files changed, 62 insertions(+), 77 deletions(-) diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 33632801bec..a17a47b451e 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -25,7 +25,10 @@ interface ChooseLocationProps { title: string body: string | JSX.Element robotType: RobotType - moveToXYCoordinate: (x: number, y: number) => Promise + moveToXYCoordinate: ( + x: number, + y: number + ) => Promise isRobotMoving: boolean } diff --git a/app/src/organisms/DropTipWizard/ExitConfirmation.tsx b/app/src/organisms/DropTipWizard/ExitConfirmation.tsx index 558207655c6..fb409919472 100644 --- a/app/src/organisms/DropTipWizard/ExitConfirmation.tsx +++ b/app/src/organisms/DropTipWizard/ExitConfirmation.tsx @@ -27,14 +27,12 @@ export function ExitConfirmation(props: ExitConfirmationProps): JSX.Element { const flowTitle = t('drop_tips') const isOnDevice = useSelector(getIsOnDevice) - if (isRobotMoving) - return ( - - ) - - return ( + return isRobotMoving ? ( + + ) : ( { /> ) : ( - <> - - {t('shared:go_back')} - - - {currentStep === POSITION_AND_BLOWOUT - ? i18n.format(t('blowout_liquid'), 'capitalize') - : i18n.format(t('drop_tips'), 'capitalize')} - - + + + + + {t('shared:go_back')} + + + {currentStep === POSITION_AND_BLOWOUT + ? i18n.format(t('blowout_liquid'), 'capitalize') + : i18n.format(t('drop_tips'), 'capitalize')} + + + )} ) @@ -104,7 +113,6 @@ interface JogToPositionProps { handleProceed: () => void body: string isRobotMoving: boolean - isExiting: boolean chainRunCommands: any currentStep: string createdMaintenanceRunId: string | null @@ -122,7 +130,6 @@ export const JogToPosition = ( handleProceed, body, isRobotMoving, - isExiting, currentStep, isOnDevice, } = props diff --git a/app/src/organisms/DropTipWizard/Success.tsx b/app/src/organisms/DropTipWizard/Success.tsx index 3d6c2289aaf..2c7cdbdfe5c 100644 --- a/app/src/organisms/DropTipWizard/Success.tsx +++ b/app/src/organisms/DropTipWizard/Success.tsx @@ -12,7 +12,6 @@ import { getIsOnDevice } from '../../redux/config' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { SmallButton } from '../../atoms/buttons' -import { BLOWOUT_SUCCESS } from './constants' interface SuccessProps { message: string @@ -20,7 +19,6 @@ interface SuccessProps { handleProceed: () => void isRobotMoving: boolean isExiting: boolean - currentStep: string } export const Success = (props: SuccessProps): JSX.Element => { const { @@ -29,7 +27,6 @@ export const Success = (props: SuccessProps): JSX.Element => { handleProceed, isRobotMoving, isExiting, - currentStep, } = props const isOnDevice = useSelector(getIsOnDevice) diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index a8c406aba24..061686644a9 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -41,7 +41,7 @@ import { ChooseLocation } from './ChooseLocation' import { JogToPosition } from './JogToPosition' import { Success } from './Success' -import type { PipetteData, CommandData } from '@opentrons/api-client' +import type { PipetteData } from '@opentrons/api-client' import type { Coordinates, PipetteModelSpecs, @@ -49,8 +49,9 @@ import type { SavePositionRunTimeCommand, CreateCommand, } from '@opentrons/shared-data' - -const RUN_REFETCH_INTERVAL = 5000 +import type { CommandData } from '@opentrons/api-client' +const RUN_REFETCH_INTERVAL_MS = 5000 +const JOG_COMMAND_TIMEOUT_MS = 10000 const MANAGED_PIPETTE_ID = 'managedPipetteId' interface MaintenanceRunManagerProps { @@ -58,7 +59,6 @@ interface MaintenanceRunManagerProps { mount: PipetteData['mount'] instrumentModelSpecs: PipetteModelSpecs closeFlow: () => void - onComplete?: () => void } export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { const { closeFlow, mount, instrumentModelSpecs, robotType } = props @@ -66,10 +66,7 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { chainRunCommands, isCommandMutationLoading: isChainCommandMutationLoading, } = useChainMaintenanceCommands() - const { - createMaintenanceCommand, - isLoading: isCommandLoading, - } = useCreateMaintenanceCommandMutation() + const { createMaintenanceCommand } = useCreateMaintenanceCommandMutation() const [createdMaintenanceRunId, setCreatedMaintenanceRunId] = React.useState< string | null @@ -109,7 +106,7 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { }) const { data: maintenanceRunData } = useCurrentMaintenanceRun({ - refetchInterval: RUN_REFETCH_INTERVAL, + refetchInterval: RUN_REFETCH_INTERVAL_MS, enabled: createdMaintenanceRunId != null, }) @@ -148,23 +145,12 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { if (maintenanceRunData?.data.id == null) { closeFlow() } else { - chainRunCommands( - maintenanceRunData?.data.id, - [{ commandType: 'home' as const, params: {} }], - true - ) - .then(() => { - deleteMaintenanceRun(maintenanceRunData?.data.id) - setIsExiting(false) - props.onComplete?.() - }) - .catch(error => { - console.error(error.message) - setErrorMessage(`error exiting: ${error.message}`) - deleteMaintenanceRun(maintenanceRunData?.data.id) + deleteMaintenanceRun(maintenanceRunData?.data.id, { + onSuccess: () => { + closeFlow() setIsExiting(false) - props.onComplete?.() - }) + }, + }) } } @@ -177,9 +163,7 @@ export function DropTipWizard(props: MaintenanceRunManagerProps): JSX.Element { instrumentModelSpecs={instrumentModelSpecs} createMaintenanceRun={createTargetedMaintenanceRun} isCreateLoading={isCreateLoading} - isRobotMoving={ - isChainCommandMutationLoading || isCommandLoading || isExiting - } + isRobotMoving={isChainCommandMutationLoading || isExiting} handleCleanUpAndClose={handleCleanUpAndClose} chainRunCommands={chainRunCommands} createRunCommand={createMaintenanceCommand} @@ -222,7 +206,7 @@ export const DropTipWizardComponent = ( // attachedInstrument, isCreateLoading, isRobotMoving, - // createRunCommand, + createRunCommand, setErrorMessage, errorMessage, isExiting, @@ -255,20 +239,15 @@ export const DropTipWizardComponent = ( } const handleJog: Jog = (axis, dir, step) => { if (createdMaintenanceRunId != null) { - chainRunCommands( - createdMaintenanceRunId, - [ - { - commandType: 'moveRelative', - params: { - pipetteId: MANAGED_PIPETTE_ID, - distance: step * dir, - axis, - }, - }, - ], - true - ) + createRunCommand({ + maintenanceRunId: createdMaintenanceRunId, + command: { + commandType: 'moveRelative', + params: { pipetteId: MANAGED_PIPETTE_ID, distance: step * dir, axis }, + }, + waitUntilComplete: true, + timeout: JOG_COMMAND_TIMEOUT_MS, + }) .then(data => {}) .catch((e: Error) => setErrorMessage(`error issuing jog command: ${e.message}`) @@ -294,7 +273,7 @@ export const DropTipWizardComponent = ( const retractAllAxesAndSavePosition = (): Promise => { if (createdMaintenanceRunId == null) - return Promise.reject( + return Promise.reject( new Error('no maintenance run present to send move commands to') ) const commands: CreateCommand[] = [ @@ -349,7 +328,10 @@ export const DropTipWizardComponent = ( ) } - const moveToXYCoordinate = (x: number, y: number): Promise => { + const moveToXYCoordinate = ( + x: number, + y: number + ): Promise => { if (createdMaintenanceRunId == null) return Promise.reject( new Error('no maintenance run present to send move commands to') @@ -358,7 +340,7 @@ export const DropTipWizardComponent = ( return retractAllAxesAndSavePosition() .then(currentPosition => { if (currentPosition != null) { - chainRunCommands( + return chainRunCommands( createdMaintenanceRunId, [ { @@ -496,7 +478,6 @@ export const DropTipWizardComponent = ( } }} isRobotMoving={isRobotMoving} - isExiting={isExiting} handleGoBack={goBack} body={ currentStep === POSITION_AND_BLOWOUT @@ -532,15 +513,14 @@ export const DropTipWizardComponent = ( } isRobotMoving={isRobotMoving} isExiting={isExiting} - currentStep={currentStep} /> ) } let handleExit: (() => void) | undefined = confirmExit - if (isRobotMoving) { + if (isRobotMoving || showConfirmExit) { handleExit = undefined - } else if (showConfirmExit || errorMessage != null) { + } else if (errorMessage != null) { handleExit = handleCleanUpAndClose } From 6c1255c9aca4787886d8bcdf842965ec785e838f Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Wed, 18 Oct 2023 15:25:43 -0400 Subject: [PATCH 04/13] feat(app): fill out new content for both desktop and ODD droptip wizard Add loading, error, and confirmation states for all droptip wizard steps. Style tiles and add content for ODD and desktop. --- .../DropTipWizard/BeforeBeginning.tsx | 70 ++++++- .../DropTipWizard/ChooseLocation.tsx | 53 ++++- .../DropTipWizard/ExitConfirmation.tsx | 1 - .../organisms/DropTipWizard/JogToPosition.tsx | 196 ++++++++++-------- app/src/organisms/DropTipWizard/Success.tsx | 5 +- app/src/organisms/DropTipWizard/index.tsx | 6 +- 6 files changed, 225 insertions(+), 106 deletions(-) diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index b165a06cdf1..1a0bf3e7925 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -16,37 +16,85 @@ import { DISPLAY_INLINE_BLOCK, JUSTIFY_SPACE_BETWEEN, PrimaryButton, + JUSTIFY_FLEX_END, } from '@opentrons/components' import { StyledText } from '../../atoms/text' +import { SmallButton, MediumButton } from '../../atoms/buttons' import { NeedHelpLink } from '../CalibrationPanels' - // TODO: get help link article 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 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 ? ( + + + + {t('before_you_begin_do_you_want_to_blowout')} + + + setFlowType('liquid_and_tips')} + buttonText={i18n.format(t('yes_blow_out_liquid'), 'capitalize')} + justifyContent={JUSTIFY_FLEX_START} + paddingLeft={SPACING.spacing24} + /> + + + { + setFlowType('only_tips') + }} + buttonText={i18n.format(t('no_proceed_to_drop_tip'), 'capitalize')} + justifyContent={JUSTIFY_FLEX_START} + paddingLeft={SPACING.spacing24} + /> + + + + + + + ) : ( {t('before_you_begin_do_you_want_to_blowout')} setFlowType('liquid_and_tips')} + onClick={() => { + setFlowType('liquid_and_tips') + }} css={ flowType === 'liquid_and_tips' ? SELECTED_OPTIONS_STYLE @@ -80,7 +128,10 @@ export const BeforeBeginning = ( justifyContent={JUSTIFY_SPACE_BETWEEN} > - + {i18n.format(t('shared:continue'), 'capitalize')} @@ -152,6 +203,11 @@ const Title = styled.h1` } ` +const TitleODD = css` + ${TYPOGRAPHY.level4HeaderSemiBold} + margin-bottom: ${SPACING.spacing16}; +` + const TILE_CONTAINER_STYLE = css` flex-direction: ${DIRECTION_COLUMN}; justify-content: ${JUSTIFY_SPACE_BETWEEN}; diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index a17a47b451e..079e16a7c77 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -8,14 +8,20 @@ import { ALIGN_CENTER, RESPONSIVENESS, JUSTIFY_SPACE_BETWEEN, + JUSTIFY_CENTER, + JUSTIFY_FLEX_END, PrimaryButton, useDeckLocationSelect, + SPACING, + TYPOGRAPHY, } from '@opentrons/components' +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 = '' @@ -30,6 +36,7 @@ interface ChooseLocationProps { y: number ) => Promise isRobotMoving: boolean + isOnDevice: boolean } export const ChooseLocation = ( @@ -42,8 +49,9 @@ export const ChooseLocation = ( robotType, moveToXYCoordinate, isRobotMoving, + isOnDevice, } = props - const { t } = useTranslation(['drop_tip_wizard', 'shared']) + const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const deckDef = getDeckDefFromRobotType(robotType) const { DeckLocationSelect, selectedLocation } = useDeckLocationSelect( robotType @@ -75,11 +83,44 @@ export const ChooseLocation = ( } } - return isRobotMoving ? ( - + if (isRobotMoving) { + return ( + + ) + } + + return isOnDevice ? ( + + + + + {title} + + {body} + + + {DeckLocationSelect} + + + + + + ) : ( {isOnDevice ? ( diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index 0a9bdcba98f..9368505e26e 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import styled, { css } from 'styled-components' +import styled from 'styled-components' import { useTranslation } from 'react-i18next' import { POSITION_AND_BLOWOUT } from './constants' import { @@ -8,6 +8,7 @@ import { ALIGN_CENTER, RESPONSIVENESS, JUSTIFY_SPACE_BETWEEN, + JUSTIFY_CENTER, PrimaryButton, SecondaryButton, SPACING, @@ -15,12 +16,13 @@ import { JUSTIFY_FLEX_END, TYPOGRAPHY, COLORS, + TEXT_ALIGN_CENTER, + Icon, + ALIGN_FLEX_END, } from '@opentrons/components' import { NeedHelpLink } from '../CalibrationPanels' import { SmallButton } from '../../atoms/buttons' import { Jog, JogControls } from '../../molecules/JogControls' -import { Portal } from '../../App/portal' -import { LegacyModalShell } from '../../molecules/LegacyModal' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { StyledText } from '../../atoms/text' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' @@ -37,18 +39,73 @@ const Header = styled.h1` ` interface ConfirmPositionProps { - handleBlowout: () => void + handlePipetteAction: () => void handleGoBack: () => void isOnDevice: boolean currentStep: string } const ConfirmPosition = (props: ConfirmPositionProps): JSX.Element | null => { - const { handleBlowout, handleGoBack, isOnDevice, currentStep } = props + const { handlePipetteAction, handleGoBack, isOnDevice, currentStep } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const flowTitle = t('drop_tips') - return ( + return isOnDevice ? ( + + + + + + + {currentStep === POSITION_AND_BLOWOUT + ? t('confirm_blowout_location', { flow: flowTitle }) + : t('confirm_drop_tip_location', { flow: flowTitle })} + + + + + + + + ) : ( { > {isOnDevice ? ( { ? i18n.format(t('blowout_liquid'), 'capitalize') : i18n.format(t('drop_tips'), 'capitalize') } - onClick={handleBlowout} + onClick={handlePipetteAction} marginRight={SPACING.spacing4} /> { > {t('shared:go_back')} - + {currentStep === POSITION_AND_BLOWOUT ? i18n.format(t('blowout_liquid'), 'capitalize') : i18n.format(t('drop_tips'), 'capitalize')} @@ -134,7 +191,6 @@ export const JogToPosition = ( isOnDevice, } = props const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) - const [showFullJogControls, setShowFullJogControls] = React.useState(false) const [ showPositionConfirmation, setShowPositionConfirmation, @@ -152,13 +208,43 @@ export const JogToPosition = ( /> ) : ( setShowPositionConfirmation(false)} isOnDevice={isOnDevice} currentStep={currentStep} /> ) } + + if (isOnDevice) { + return ( + + + + + + + + setShowPositionConfirmation(true)} + /> + + + + ) + } + return ( - {isOnDevice ? ( + <> + - - - { - setShowFullJogControls(true) - }} - /> - setShowPositionConfirmation(true)} - /> + + + + {t('shared:go_back')} + + setShowPositionConfirmation(true)}> + {t('shared:confirm_position')} + - - {showFullJogControls ? ( - - {t('move_to_a1_position')} - - } - footer={ - { - setShowFullJogControls(false) - }} - /> - } - > - - - ) : null} - - ) : ( - <> - - - - - - {t('shared:go_back')} - - setShowPositionConfirmation(true)}> - {t('shared:confirm_position')} - - - - - )} + ) } diff --git a/app/src/organisms/DropTipWizard/Success.tsx b/app/src/organisms/DropTipWizard/Success.tsx index 2c7cdbdfe5c..6afc9327c86 100644 --- a/app/src/organisms/DropTipWizard/Success.tsx +++ b/app/src/organisms/DropTipWizard/Success.tsx @@ -1,4 +1,3 @@ -import { useSelector } from 'react-redux' import * as React from 'react' import { useTranslation } from 'react-i18next' import { @@ -8,7 +7,6 @@ import { JUSTIFY_FLEX_END, Flex, } from '@opentrons/components' -import { getIsOnDevice } from '../../redux/config' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { SmallButton } from '../../atoms/buttons' @@ -19,6 +17,7 @@ interface SuccessProps { handleProceed: () => void isRobotMoving: boolean isExiting: boolean + isOnDevice: boolean } export const Success = (props: SuccessProps): JSX.Element => { const { @@ -27,8 +26,8 @@ export const Success = (props: SuccessProps): JSX.Element => { handleProceed, isRobotMoving, isExiting, + isOnDevice, } = props - const isOnDevice = useSelector(getIsOnDevice) const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index 061686644a9..b9f2dbd767b 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -41,7 +41,7 @@ import { ChooseLocation } from './ChooseLocation' import { JogToPosition } from './JogToPosition' import { Success } from './Success' -import type { PipetteData } from '@opentrons/api-client' +import type { PipetteData, CommandData } from '@opentrons/api-client' import type { Coordinates, PipetteModelSpecs, @@ -49,7 +49,6 @@ import type { SavePositionRunTimeCommand, CreateCommand, } from '@opentrons/shared-data' -import type { CommandData } from '@opentrons/api-client' const RUN_REFETCH_INTERVAL_MS = 5000 const JOG_COMMAND_TIMEOUT_MS = 10000 const MANAGED_PIPETTE_ID = 'managedPipetteId' @@ -396,6 +395,7 @@ export const DropTipWizardComponent = ( {...{ handleCreateAndSetup, isCreateLoading, + isOnDevice, }} /> ) @@ -429,6 +429,7 @@ export const DropTipWizardComponent = ( } moveToXYCoordinate={moveToXYCoordinate} isRobotMoving={isRobotMoving} + isOnDevice={isOnDevice} /> ) } else if ( @@ -513,6 +514,7 @@ export const DropTipWizardComponent = ( } isRobotMoving={isRobotMoving} isExiting={isExiting} + isOnDevice={isOnDevice} /> ) } From 510aaeb21dc6db4ff0d7988e64764ffd5dba5835 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Thu, 19 Oct 2023 11:22:21 -0400 Subject: [PATCH 05/13] remove blank assets from jog tile --- .../videos/droptip-wizard/Blowout-Liquid.webm | Bin 0 -> 24110 bytes .../videos/droptip-wizard/Drop-tip.webm | Bin 0 -> 40737 bytes .../DropTipWizard/BeforeBeginning.tsx | 34 +++++++++++++----- .../organisms/DropTipWizard/JogToPosition.tsx | 9 +++-- 4 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 app/src/assets/videos/droptip-wizard/Blowout-Liquid.webm create mode 100644 app/src/assets/videos/droptip-wizard/Drop-tip.webm diff --git a/app/src/assets/videos/droptip-wizard/Blowout-Liquid.webm b/app/src/assets/videos/droptip-wizard/Blowout-Liquid.webm new file mode 100644 index 0000000000000000000000000000000000000000..0da6aa63c8fde023e79bf17b3c808be74de0c76b GIT binary patch literal 24110 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 Tg0?ZChA2D#y&~<4M^O9^M@rmo literal 0 HcmV?d00001 diff --git a/app/src/assets/videos/droptip-wizard/Drop-tip.webm b/app/src/assets/videos/droptip-wizard/Drop-tip.webm new file mode 100644 index 0000000000000000000000000000000000000000..aa11df0e7da0dc169b97f6d47fc572a04cbb011b GIT binary patch literal 40737 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

L1MLE_5A%soiYFq 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 literal 0 HcmV?d00001 diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 1a0bf3e7925..3304fd3b259 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -21,6 +21,10 @@ import { import { StyledText } from '../../atoms/text' 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 = '' @@ -101,10 +105,17 @@ export const BeforeBeginning = ( : UNSELECTED_OPTIONS_STYLE } > - {/* */} + {t('yes_blow_out_liquid')} - {/* */} + {t('no_proceed_to_drop_tip')} diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index 9368505e26e..07bed62f48f 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -264,9 +264,12 @@ export const JogToPosition = ( {body} - - - + {/* no animations */} + <> From 83f41a833330ebe4414250882199cc02f4934338 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Thu, 19 Oct 2023 14:39:45 -0400 Subject: [PATCH 06/13] fix Promise typing error --- .../organisms/DropTipWizard/ChooseLocation.tsx | 5 +---- app/src/organisms/DropTipWizard/index.tsx | 16 ++++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 079e16a7c77..8f4aec94427 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -31,10 +31,7 @@ interface ChooseLocationProps { title: string body: string | JSX.Element robotType: RobotType - moveToXYCoordinate: ( - x: number, - y: number - ) => Promise + moveToXYCoordinate: (x: number, y: number) => Promise isRobotMoving: boolean isOnDevice: boolean } diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index b9f2dbd767b..1cb5acc6c6e 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -270,7 +270,7 @@ export const DropTipWizardComponent = ( ) } - const retractAllAxesAndSavePosition = (): Promise => { + const retractAllAxesAndSavePosition = (): Promise => { if (createdMaintenanceRunId == null) return Promise.reject( new Error('no maintenance run present to send move commands to') @@ -320,17 +320,18 @@ export const DropTipWizardComponent = ( ) } }) - .catch(e => + .catch(e => { setErrorMessage( `error retracting x and y axes or saving position: ${e.message}` ) - ) + return null + }) } const moveToXYCoordinate = ( x: number, y: number - ): Promise => { + ): Promise => { if (createdMaintenanceRunId == null) return Promise.reject( new Error('no maintenance run present to send move commands to') @@ -361,9 +362,12 @@ export const DropTipWizardComponent = ( ], true ) - } + } else return null + }) + .catch(e => { + setErrorMessage(`error moving to position: ${e.message}`) + return null }) - .catch(e => setErrorMessage(`error moving to position: ${e.message}`)) } let modalContent: JSX.Element =

UNASSIGNED STEP
From a81b41ad3a459f05a86380f4324f31c41603bdad Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Fri, 20 Oct 2023 12:49:19 -0400 Subject: [PATCH 07/13] handle error in movetoxy --- app/src/organisms/DropTipWizard/BeforeBeginning.tsx | 8 ++++++++ app/src/organisms/DropTipWizard/ChooseLocation.tsx | 8 ++++++-- app/src/organisms/DropTipWizard/index.tsx | 5 +++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 3304fd3b259..68ab633aefd 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -17,6 +17,8 @@ import { JUSTIFY_SPACE_BETWEEN, PrimaryButton, JUSTIFY_FLEX_END, + POSITION_ABSOLUTE, + POSITION_RELATIVE, } from '@opentrons/components' import { StyledText } from '../../atoms/text' import { SmallButton, MediumButton } from '../../atoms/buttons' @@ -105,6 +107,12 @@ export const BeforeBeginning = ( : UNSELECTED_OPTIONS_STYLE } > + diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index 1cb5acc6c6e..13a1db31325 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -212,6 +212,10 @@ export const DropTipWizardComponent = ( createdMaintenanceRunId, instrumentModelSpecs, } = props + console.log( + '🚀 ~ file: index.tsx:215 ~ createdMaintenanceRunId:', + createdMaintenanceRunId + ) const isOnDevice = useSelector(getIsOnDevice) const { t, i18n } = useTranslation('drop_tip_wizard') @@ -434,6 +438,7 @@ export const DropTipWizardComponent = ( moveToXYCoordinate={moveToXYCoordinate} isRobotMoving={isRobotMoving} isOnDevice={isOnDevice} + setErrorMessage={setErrorMessage} /> ) } else if ( From 6c61011fdb7358d45e0022722d895781825c47cd Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Fri, 20 Oct 2023 14:40:54 -0400 Subject: [PATCH 08/13] dont show exit confirmation screen if exit on last step (success) --- app/src/organisms/DropTipWizard/index.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index 13a1db31325..55cebeac151 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -212,10 +212,6 @@ export const DropTipWizardComponent = ( createdMaintenanceRunId, instrumentModelSpecs, } = props - console.log( - '🚀 ~ file: index.tsx:215 ~ createdMaintenanceRunId:', - createdMaintenanceRunId - ) const isOnDevice = useSelector(getIsOnDevice) const { t, i18n } = useTranslation('drop_tip_wizard') @@ -540,7 +536,11 @@ export const DropTipWizardComponent = ( title={i18n.format(t('drop_tips'), 'capitalize')} currentStep={shouldDispenseLiquid != null ? currentStepIndex + 1 : null} totalSteps={DropTipWizardSteps.length} - onExit={handleExit} + onExit={ + currentStepIndex === DropTipWizardSteps.length - 1 + ? handleCleanUpAndClose + : handleExit + } /> ) From 9bd45a06ca59a8c1c372dd39d42d1ebadd2e7783 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Fri, 20 Oct 2023 14:52:19 -0400 Subject: [PATCH 09/13] fix linting --- app/src/organisms/DropTipWizard/BeforeBeginning.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 68ab633aefd..38c4a1555b4 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -18,7 +18,6 @@ import { PrimaryButton, JUSTIFY_FLEX_END, POSITION_ABSOLUTE, - POSITION_RELATIVE, } from '@opentrons/components' import { StyledText } from '../../atoms/text' import { SmallButton, MediumButton } from '../../atoms/buttons' From 4c840800cfbae2f40e618407189ad54f3dcafaaa Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Fri, 20 Oct 2023 15:31:06 -0400 Subject: [PATCH 10/13] remove need help link for now --- .../localization/en/drop_tip_wizard.json | 1 + .../DropTipWizard/BeforeBeginning.tsx | 11 ++- .../DropTipWizard/ChooseLocation.tsx | 17 ++--- .../organisms/DropTipWizard/JogToPosition.tsx | 67 +++++++++---------- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/app/src/assets/localization/en/drop_tip_wizard.json b/app/src/assets/localization/en/drop_tip_wizard.json index 58058a3c447..414d6f09267 100644 --- a/app/src/assets/localization/en/drop_tip_wizard.json +++ b/app/src/assets/localization/en/drop_tip_wizard.json @@ -12,6 +12,7 @@ "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.", diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 38c4a1555b4..9c2eea5870e 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -21,13 +21,13 @@ import { } from '@opentrons/components' import { StyledText } from '../../atoms/text' import { SmallButton, MediumButton } from '../../atoms/buttons' -import { NeedHelpLink } from '../CalibrationPanels' +// 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 @@ -148,11 +148,8 @@ export const BeforeBeginning = ( {t('no_proceed_to_drop_tip')}
- - + + {/* */} void @@ -117,7 +116,7 @@ export const ChooseLocation = ( @@ -129,14 +128,10 @@ export const ChooseLocation = ( body={body} rightElement={DeckLocationSelect} footer={ - - + + {/* */} - {t('shared:confirm_position')} + {i18n.format(t('move_to_slot'), 'capitalize')} } diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index 07bed62f48f..30de57a365e 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -20,7 +20,7 @@ import { Icon, ALIGN_FLEX_END, } from '@opentrons/components' -import { NeedHelpLink } from '../CalibrationPanels' +// import { NeedHelpLink } from '../CalibrationPanels' import { SmallButton } from '../../atoms/buttons' import { Jog, JogControls } from '../../molecules/JogControls' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' @@ -29,7 +29,7 @@ import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' import { PipetteModelSpecs } from '@opentrons/shared-data' // TODO: get help link article URL -const NEED_HELP_URL = '' +// const NEED_HELP_URL = '' const Header = styled.h1` ${TYPOGRAPHY.h1Default} @@ -140,11 +140,11 @@ const ConfirmPosition = (props: ConfirmPositionProps): JSX.Element | null => { - + {/* */} - - - - - - - setShowPositionConfirmation(true)} - /> - + return isOnDevice ? ( + + + + + + + + setShowPositionConfirmation(true)} + /> - ) - } - - return ( + + ) : ( {i18n.format(t('position_the_pipette'), 'capitalize')} - {body} + {body} {/* no animations */} - + {/* */} {t('shared:go_back')} From e7ff44082bcf33cf947ebdd86326fb3506ffc4a7 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 24 Oct 2023 10:47:34 -0400 Subject: [PATCH 11/13] post-review changes: text, large ternaries, styling --- .../localization/en/drop_tip_wizard.json | 2 +- .../DropTipWizard/BeforeBeginning.tsx | 211 +++++++------- .../DropTipWizard/ChooseLocation.tsx | 100 +++---- .../DropTipWizard/ExitConfirmation.tsx | 5 +- .../organisms/DropTipWizard/JogToPosition.tsx | 270 ++++++++---------- app/src/organisms/DropTipWizard/index.tsx | 42 ++- 6 files changed, 306 insertions(+), 324 deletions(-) diff --git a/app/src/assets/localization/en/drop_tip_wizard.json b/app/src/assets/localization/en/drop_tip_wizard.json index 414d6f09267..bbc67be12fb 100644 --- a/app/src/assets/localization/en/drop_tip_wizard.json +++ b/app/src/assets/localization/en/drop_tip_wizard.json @@ -1,7 +1,7 @@ { "before_you_begin_do_you_want_to_blowout": "Before you begin, do you need to preserve aspirated liquid?", - "blowout_liquid": "Blow out liquid", "blowout_complete": "blowout complete", + "blowout_liquid": "Blow out liquid", "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?", diff --git a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx index 9c2eea5870e..221cf579259 100644 --- a/app/src/organisms/DropTipWizard/BeforeBeginning.tsx +++ b/app/src/organisms/DropTipWizard/BeforeBeginning.tsx @@ -47,118 +47,125 @@ export const BeforeBeginning = ( handleCreateAndSetup(flowType === 'liquid_and_tips') } - return isOnDevice ? ( - - - - {t('before_you_begin_do_you_want_to_blowout')} + if (isOnDevice) { + return ( + + + + {t('before_you_begin_do_you_want_to_blowout')} + + + setFlowType('liquid_and_tips')} + buttonText={i18n.format(t('yes_blow_out_liquid'), 'capitalize')} + justifyContent={JUSTIFY_FLEX_START} + paddingLeft={SPACING.spacing24} + /> + + + { + setFlowType('only_tips') + }} + buttonText={i18n.format( + t('no_proceed_to_drop_tip'), + 'capitalize' + )} + justifyContent={JUSTIFY_FLEX_START} + paddingLeft={SPACING.spacing24} + /> + - - setFlowType('liquid_and_tips')} - buttonText={i18n.format(t('yes_blow_out_liquid'), 'capitalize')} - justifyContent={JUSTIFY_FLEX_START} - paddingLeft={SPACING.spacing24} + + - - + ) + } else { + return ( + + {t('before_you_begin_do_you_want_to_blowout')} + + { - setFlowType('only_tips') + setFlowType('liquid_and_tips') }} - buttonText={i18n.format(t('no_proceed_to_drop_tip'), 'capitalize')} - justifyContent={JUSTIFY_FLEX_START} - paddingLeft={SPACING.spacing24} - /> - - - - - - - ) : ( - - {t('before_you_begin_do_you_want_to_blowout')} - - { - setFlowType('liquid_and_tips') - }} - css={ - flowType === 'liquid_and_tips' - ? SELECTED_OPTIONS_STYLE - : UNSELECTED_OPTIONS_STYLE - } - > + css={ + flowType === 'liquid_and_tips' + ? SELECTED_OPTIONS_STYLE + : UNSELECTED_OPTIONS_STYLE + } + > + + + {t('yes_blow_out_liquid')} + - - {t('yes_blow_out_liquid')} + + {t('no_proceed_to_drop_tip')} + - setFlowType('only_tips')} - css={ - flowType === 'only_tips' - ? SELECTED_OPTIONS_STYLE - : UNSELECTED_OPTIONS_STYLE - } - > - - {t('no_proceed_to_drop_tip')} + {i18n.format(t('shared:continue'), 'capitalize')} + - - {/* */} - - {i18n.format(t('shared:continue'), 'capitalize')} - - - - ) + ) + } } const UNSELECTED_OPTIONS_STYLE = css` @@ -225,7 +232,7 @@ const Title = styled.h1` } ` -const TitleODD = css` +const ODD_TITLE_STYLE = css` ${TYPOGRAPHY.level4HeaderSemiBold} margin-bottom: ${SPACING.spacing16}; ` diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index b6c7b15b8b4..469c41519b1 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -71,12 +71,6 @@ export const ChooseLocation = ( ) { const targetX = slotX + xDimension / 2 const targetY = slotY + yDimension / 2 - console.log( - 'MOVE TO selected location: ', - selectedLocation, - targetX, - targetY - ) moveToXYCoordinate(targetX, targetY) .then(() => handleProceed()) .catch(e => setErrorMessage(`${e.message}`)) @@ -84,60 +78,66 @@ export const ChooseLocation = ( } if (isRobotMoving) { - return ( - - ) + return } - return isOnDevice ? ( - - + if (isOnDevice) { + return ( + - - {title} - - {body} + + + {title} + + {body} + + + {DeckLocationSelect} + - - {DeckLocationSelect} + + - - + + {/* */} + + {i18n.format(t('move_to_slot'), 'capitalize')} + + + } /> - - ) : ( - - - {/* */} - - {i18n.format(t('move_to_slot'), 'capitalize')} - - - } - /> - - ) + ) + } } const TILE_CONTAINER_STYLE = css` diff --git a/app/src/organisms/DropTipWizard/ExitConfirmation.tsx b/app/src/organisms/DropTipWizard/ExitConfirmation.tsx index bc8971bfab3..a0ab8178c61 100644 --- a/app/src/organisms/DropTipWizard/ExitConfirmation.tsx +++ b/app/src/organisms/DropTipWizard/ExitConfirmation.tsx @@ -28,10 +28,7 @@ export function ExitConfirmation(props: ExitConfirmationProps): JSX.Element { const isOnDevice = useSelector(getIsOnDevice) return isRobotMoving ? ( - + ) : ( { const { i18n, t } = useTranslation(['drop_tip_wizard', 'shared']) const flowTitle = t('drop_tips') - return isOnDevice ? ( - + if (isOnDevice) { + return ( - - - - - {currentStep === POSITION_AND_BLOWOUT - ? t('confirm_blowout_location', { flow: flowTitle }) - : t('confirm_drop_tip_location', { flow: flowTitle })} - - - - - - - - ) : ( - - {isOnDevice ? ( + + + + + {currentStep === POSITION_AND_BLOWOUT + ? t('confirm_blowout_location', { flow: flowTitle }) + : t('confirm_drop_tip_location', { flow: flowTitle })} + + + + - - ) : ( + + ) + } else { + return ( + { - )} -
- ) + + ) + } } interface JogToPositionProps { @@ -170,11 +150,7 @@ interface JogToPositionProps { handleProceed: () => void body: string isRobotMoving: boolean - chainRunCommands: any currentStep: string - createdMaintenanceRunId: string | null - pipetteId: string - instrumentModelSpecs: PipetteModelSpecs isOnDevice: boolean } @@ -216,75 +192,79 @@ export const JogToPosition = ( ) } - return isOnDevice ? ( - - - - - - - - setShowPositionConfirmation(true)} - /> - - - - ) : ( - - - -
- {i18n.format(t('position_the_pipette'), 'capitalize')} -
- {body} + if (isOnDevice) { + return ( + + + + + + + + setShowPositionConfirmation(true)} + /> + - {/* no animations */} - - <> - - - {/* */} - - - {t('shared:go_back')} - - setShowPositionConfirmation(true)}> - {t('shared:confirm_position')} - + ) + } else { + return ( + + + +
+ {i18n.format(t('position_the_pipette'), 'capitalize')} +
+ {body}
+ {/* no animations */} +
- -
- ) + <> + + + {/* */} + + + {t('shared:go_back')} + + setShowPositionConfirmation(true)}> + {t('shared:confirm_position')} + + + + +
+ ) + } } diff --git a/app/src/organisms/DropTipWizard/index.tsx b/app/src/organisms/DropTipWizard/index.tsx index 55cebeac151..e044f775be1 100644 --- a/app/src/organisms/DropTipWizard/index.tsx +++ b/app/src/organisms/DropTipWizard/index.tsx @@ -249,7 +249,7 @@ export const DropTipWizardComponent = ( }) .then(data => {}) .catch((e: Error) => - setErrorMessage(`error issuing jog command: ${e.message}`) + setErrorMessage(`Error issuing jog command: ${e.message}`) ) } } @@ -266,7 +266,7 @@ export const DropTipWizardComponent = ( setShouldDispenseLiquid(shouldDispenseLiquid) }) .catch(e => - setErrorMessage(`error setting up blowout/droptip: ${e.message}`) + setErrorMessage(`Error setting up blowout/droptip: ${e.message}`) ) } @@ -307,7 +307,7 @@ export const DropTipWizardComponent = ( .then(responses => { if (responses.length !== commands.length) { return Promise.reject( - new Error('not all commands executed successfully') + new Error('Not all commands executed successfully') ) } const currentPosition = (responses[responses.length - 1] @@ -316,13 +316,13 @@ export const DropTipWizardComponent = ( return Promise.resolve(currentPosition) } else { return Promise.reject( - new Error('current position could not be saved') + new Error('Current position could not be saved') ) } }) .catch(e => { setErrorMessage( - `error retracting x and y axes or saving position: ${e.message}` + `Error retracting x and y axes or saving position: ${e.message}` ) return null }) @@ -407,6 +407,16 @@ export const DropTipWizardComponent = ( currentStep === CHOOSE_BLOWOUT_LOCATION || currentStep === CHOOSE_DROP_TIP_LOCATION ) { + let bodyTextKey + if (currentStep === CHOOSE_BLOWOUT_LOCATION) { + bodyTextKey = isOnDevice + ? 'select_blowout_slot_odd' + : 'select_blowout_slot' + } else { + bodyTextKey = isOnDevice + ? 'select_drop_tip_slot_odd' + : 'select_drop_tip_slot' + } modalContent = ( }} /> } @@ -469,12 +471,12 @@ export const DropTipWizardComponent = ( retractAllAxesAndSavePosition() .then(() => proceed()) .catch(e => - setErrorMessage(`error moving to position: ${e.message}`) + setErrorMessage(`Error moving to position: ${e.message}`) ) }) .catch(e => setErrorMessage( - `error issuing ${ + `Error issuing ${ currentStep === POSITION_AND_BLOWOUT ? 'blowout' : 'drop tip' @@ -490,10 +492,6 @@ export const DropTipWizardComponent = ( ? t('position_and_blowout') : t('position_and_drop_tip') } - createdMaintenanceRunId={createdMaintenanceRunId} - pipetteId={MANAGED_PIPETTE_ID} - instrumentModelSpecs={instrumentModelSpecs} - chainRunCommands={chainRunCommands} currentStep={currentStep} isOnDevice={isOnDevice} /> @@ -524,9 +522,9 @@ export const DropTipWizardComponent = ( ) } - let handleExit: (() => void) | undefined = confirmExit + let handleExit: (() => void) | null = confirmExit if (isRobotMoving || showConfirmExit) { - handleExit = undefined + handleExit = null } else if (errorMessage != null) { handleExit = handleCleanUpAndClose } From ce7d86779153055ac71dd43cc95d69a01de9d96c Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 24 Oct 2023 13:07:42 -0400 Subject: [PATCH 12/13] fix button alignment in ChooseLocation component --- app/src/organisms/DropTipWizard/ChooseLocation.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/organisms/DropTipWizard/ChooseLocation.tsx b/app/src/organisms/DropTipWizard/ChooseLocation.tsx index 469c41519b1..deaedcc7b0a 100644 --- a/app/src/organisms/DropTipWizard/ChooseLocation.tsx +++ b/app/src/organisms/DropTipWizard/ChooseLocation.tsx @@ -87,10 +87,11 @@ export const ChooseLocation = ( padding={SPACING.spacing32} flexDirection={DIRECTION_COLUMN} justifyContent={JUSTIFY_SPACE_BETWEEN} + flex="1" > {body} - + {DeckLocationSelect} From a503baf20108e2d20a47f2e814cc97fc022cd9f5 Mon Sep 17 00:00:00 2001 From: ncdiehl11 Date: Tue, 24 Oct 2023 13:20:17 -0400 Subject: [PATCH 13/13] remove unused import --- app/src/organisms/DropTipWizard/JogToPosition.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/organisms/DropTipWizard/JogToPosition.tsx b/app/src/organisms/DropTipWizard/JogToPosition.tsx index 465259b2a88..dd06a50fc57 100644 --- a/app/src/organisms/DropTipWizard/JogToPosition.tsx +++ b/app/src/organisms/DropTipWizard/JogToPosition.tsx @@ -26,7 +26,6 @@ import { Jog, JogControls } from '../../molecules/JogControls' import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal' import { StyledText } from '../../atoms/text' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' -import { PipetteModelSpecs } from '@opentrons/shared-data' // TODO: get help link article URL // const NEED_HELP_URL = ''