diff --git a/app/src/App/OnDeviceDisplayApp.tsx b/app/src/App/OnDeviceDisplayApp.tsx index 42335754432..8dc3a362f80 100644 --- a/app/src/App/OnDeviceDisplayApp.tsx +++ b/app/src/App/OnDeviceDisplayApp.tsx @@ -178,7 +178,7 @@ export const OnDeviceDisplayApp = (): JSX.Element => { // TODO (sb:6/12/23) Create a notification manager to set up preference and order of takeover modals return ( - + diff --git a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx index 8dc996c3374..e1a255abdcb 100644 --- a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx +++ b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx @@ -23,6 +23,8 @@ import { } from '@opentrons/components' import { useAcknowledgeEstopDisengageMutation } from '@opentrons/react-api-client' +import { usePlacePlateReaderLid } from '/app/resources/modules' + import { getTopPortalEl } from '/app/App/portal' import { SmallButton } from '/app/atoms/buttons' @@ -43,6 +45,7 @@ interface EstopPressedModalProps { isDismissedModal?: boolean setIsDismissedModal?: (isDismissedModal: boolean) => void isWaitingForLogicalDisengage: boolean + isWaitingForPlateReaderLidPlacement: boolean setShouldSeeLogicalDisengage: () => void } @@ -52,6 +55,7 @@ export function EstopPressedModal({ isDismissedModal, setIsDismissedModal, isWaitingForLogicalDisengage, + isWaitingForPlateReaderLidPlacement, setShouldSeeLogicalDisengage, }: EstopPressedModalProps): JSX.Element { const isOnDevice = useSelector(getIsOnDevice) @@ -61,6 +65,7 @@ export function EstopPressedModal({ isEngaged={isEngaged} closeModal={closeModal} isWaitingForLogicalDisengage={isWaitingForLogicalDisengage} + isWaitingForPlateReaderLidPlacement={isWaitingForPlateReaderLidPlacement} setShouldSeeLogicalDisengage={setShouldSeeLogicalDisengage} /> ) : ( @@ -71,6 +76,7 @@ export function EstopPressedModal({ closeModal={closeModal} setIsDismissedModal={setIsDismissedModal} isWaitingForLogicalDisengage={isWaitingForLogicalDisengage} + isWaitingForPlateReaderLidPlacement={isWaitingForPlateReaderLidPlacement} setShouldSeeLogicalDisengage={setShouldSeeLogicalDisengage} /> ) : null} @@ -84,11 +90,16 @@ function TouchscreenModal({ isEngaged, closeModal, isWaitingForLogicalDisengage, + isWaitingForPlateReaderLidPlacement, setShouldSeeLogicalDisengage, }: EstopPressedModalProps): JSX.Element { const { t } = useTranslation(['device_settings', 'branded']) const [isResuming, setIsResuming] = React.useState(false) const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation() + + const { placeReaderLid, isPlacing } = usePlacePlateReaderLid({ + pipetteInfo: null + }) const modalHeader: OddModalHeaderBaseProps = { title: t('estop_pressed'), iconName: 'ot-alert', @@ -102,6 +113,7 @@ function TouchscreenModal({ setIsResuming(true) acknowledgeEstopDisengage(null) setShouldSeeLogicalDisengage() + placeReaderLid() closeModal() } return ( @@ -131,15 +143,15 @@ function TouchscreenModal({ data-testid="Estop_pressed_button" width="100%" iconName={ - isResuming || isWaitingForLogicalDisengage + isResuming || isPlacing || isWaitingForLogicalDisengage || isWaitingForPlateReaderLidPlacement ? 'ot-spinner' : undefined } iconPlacement={ - isResuming || isWaitingForLogicalDisengage ? 'startIcon' : undefined + isResuming || isPlacing || isWaitingForLogicalDisengage || isWaitingForPlateReaderLidPlacement ? 'startIcon' : undefined } buttonText={t('resume_robot_operations')} - disabled={isEngaged || isResuming || isWaitingForLogicalDisengage} + disabled={isEngaged || isResuming || isPlacing || isWaitingForLogicalDisengage || isWaitingForPlateReaderLidPlacement} onClick={handleClick} /> @@ -152,11 +164,15 @@ function DesktopModal({ closeModal, setIsDismissedModal, isWaitingForLogicalDisengage, + isWaitingForPlateReaderLidPlacement, setShouldSeeLogicalDisengage, }: EstopPressedModalProps): JSX.Element { const { t } = useTranslation('device_settings') const [isResuming, setIsResuming] = React.useState(false) const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation() + const { placeReaderLid, isPlacing } = usePlacePlateReaderLid({ + pipetteInfo: null + }) const handleCloseModal = (): void => { if (setIsDismissedModal != null) { @@ -182,6 +198,7 @@ function DesktopModal({ { onSuccess: () => { setShouldSeeLogicalDisengage() + placeReaderLid() closeModal() }, onError: (error: any) => { @@ -204,14 +221,14 @@ function DesktopModal({ - {isResuming || isWaitingForLogicalDisengage ? ( + {isResuming || isPlacing || isWaitingForLogicalDisengage || isWaitingForPlateReaderLidPlacement ? ( ) : null} {t('resume_robot_operations')} diff --git a/app/src/resources/modules/hooks/index.ts b/app/src/resources/modules/hooks/index.ts index c38e5f46140..c26e43c8bfc 100644 --- a/app/src/resources/modules/hooks/index.ts +++ b/app/src/resources/modules/hooks/index.ts @@ -1 +1,2 @@ export * from './useAttachedModules' +export * from './usePlacePlateReaderLid' diff --git a/app/src/resources/modules/hooks/useDropPlateReaderLid.ts b/app/src/resources/modules/hooks/useDropPlateReaderLid.ts deleted file mode 100644 index b0234647c84..00000000000 --- a/app/src/resources/modules/hooks/useDropPlateReaderLid.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { useRobotControlCommands } from '/app/resources/maintenance_runs' - -import type { CreateCommand } from '@opentrons/shared-data' -import type { - UseRobotControlCommandsProps, - UseRobotControlCommandsResult, -} from '/app/resources/maintenance_runs' - -interface UseHomePipettesResult { - isHoming: UseRobotControlCommandsResult['isExecuting'] - homePipettes: UseRobotControlCommandsResult['executeCommands'] -} - -export type UseDropPlateReaderLidProps = Pick< - UseRobotControlCommandsProps, - 'pipetteInfo' | 'onSettled' -> - -export function useDropPlateReaderLid( - props: UseDropPlateReaderLidProps -): UseHomePipettesResult { - const { executeCommands, isExecuting } = useRobotControlCommands({ - ...props, - commands: [LOAD_PLATE_READER, DROP_PLATE_READER_LID], - continuePastCommandFailure: true, - }) - - return { - isHoming: isExecuting, - homePipettes: executeCommands, - } -} - -const LOAD_PLATE_READER: CreateCommand = { - commandType: 'loadModule' as const, - params: { model: 'absorbanceReaderV1', location: { slotName: 'C3' } }, -} - -const DROP_PLATE_READER_LID: CreateCommand = { - commandType: 'moveLabware' as const, - params: { - labwareId: 'absorbanceReaderV1LidC3', - newLocation: { slotName: 'C3' }, - strategy: 'usingGripper', - }, -} diff --git a/app/src/resources/modules/hooks/usePlacePlateReaderLid.ts b/app/src/resources/modules/hooks/usePlacePlateReaderLid.ts new file mode 100644 index 00000000000..5fcacd48cc2 --- /dev/null +++ b/app/src/resources/modules/hooks/usePlacePlateReaderLid.ts @@ -0,0 +1,49 @@ +import { useRobotControlCommands } from '/app/resources/maintenance_runs' + +import { LabwareLocation, type CreateCommand } from '@opentrons/shared-data' +import type { + UseRobotControlCommandsProps, + UseRobotControlCommandsResult, +} from '/app/resources/maintenance_runs' + +interface UsePlacePlateReaderLidResult { + isPlacing: UseRobotControlCommandsResult['isExecuting'] + placeReaderLid: UseRobotControlCommandsResult['executeCommands'] +} + +export type UsePlacePlateReaderLidProps = Pick< + UseRobotControlCommandsProps, + 'pipetteInfo' | 'onSettled' +> + +// TODO: Need to conditionally run this function based on `runs/currentState` value +export function usePlacePlateReaderLid( + props: UsePlacePlateReaderLidProps +): UsePlacePlateReaderLidResult { + const labwareId: string = 'absorbanceReaderV1LidC3' + const location: LabwareLocation = {slotName: 'C3'} + + const LOAD_PLATE_READER: CreateCommand = { + commandType: 'loadModule' as const, + params: { model: 'absorbanceReaderV1', location: location }, + } + + const PLACE_READER_LID: CreateCommand = { + commandType: 'unsafe/placeLabware' as const, + params: { + labwareId: labwareId, + location: location, + }, + } + + const { executeCommands, isExecuting } = useRobotControlCommands({ + ...props, + commands: [LOAD_PLATE_READER, PLACE_READER_LID], + continuePastCommandFailure: true, + }) + + return { + isPlacing: isExecuting, + placeReaderLid: executeCommands, + } +} diff --git a/shared-data/command/types/unsafe.ts b/shared-data/command/types/unsafe.ts index d24a6f8e054..6b20b18c49b 100644 --- a/shared-data/command/types/unsafe.ts +++ b/shared-data/command/types/unsafe.ts @@ -1,4 +1,4 @@ -import type { CommonCommandRunTimeInfo, CommonCommandCreateInfo } from '.' +import type { CommonCommandRunTimeInfo, CommonCommandCreateInfo, LabwareLocation } from '.' import type { MotorAxes } from '../../js/types' export type UnsafeRunTimeCommand = @@ -7,6 +7,7 @@ export type UnsafeRunTimeCommand = | UnsafeUpdatePositionEstimatorsRunTimeCommand | UnsafeEngageAxesRunTimeCommand | UnsafeUngripLabwareRunTimeCommand + | UnsafePlaceLabwareRunTimeCommand export type UnsafeCreateCommand = | UnsafeBlowoutInPlaceCreateCommand @@ -14,6 +15,7 @@ export type UnsafeCreateCommand = | UnsafeUpdatePositionEstimatorsCreateCommand | UnsafeEngageAxesCreateCommand | UnsafeUngripLabwareCreateCommand + | UnsafePlaceLabwareCreateCommand export interface UnsafeBlowoutInPlaceParams { pipetteId: string @@ -85,3 +87,17 @@ export interface UnsafeUngripLabwareRunTimeCommand UnsafeUngripLabwareCreateCommand { result?: any } +export interface UnsafePlaceLabwareParams { + labwareId: string, + location: LabwareLocation, +} +export interface UnsafePlaceLabwareCreateCommand + extends CommonCommandCreateInfo { + commandType: 'unsafe/placeLabware' + params: UnsafePlaceLabwareParams +} +export interface UnsafePlaceLabwareRunTimeCommand + extends CommonCommandRunTimeInfo, + UnsafePlaceLabwareCreateCommand { + result?: any +}