Skip to content

Commit

Permalink
refactor estopPressed
Browse files Browse the repository at this point in the history
  • Loading branch information
vegano1 committed Oct 24, 2024
1 parent 6c4de3e commit de39cbe
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 154 deletions.
2 changes: 1 addition & 1 deletion app/src/App/OnDeviceDisplayApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export const OnDeviceDisplayApp = (): JSX.Element => {
<>
<IncompatibleModuleTakeover isOnDevice={true} />
<MaintenanceRunTakeover>
<EstopTakeover />
<EstopTakeover />
<FirmwareUpdateTakeover />
<NiceModal.Provider>
<ToasterOven>
Expand Down
134 changes: 42 additions & 92 deletions app/src/organisms/EmergencyStop/EstopPressedModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,48 +41,33 @@ import type { ModalProps } from '@opentrons/components'
interface EstopPressedModalProps {
isEngaged: boolean
closeModal: () => void
isDismissedModal?: boolean
setIsDismissedModal?: (isDismissedModal: boolean) => void
isWaitingForLogicalDisengage: boolean
isWaitingForPlateReaderLidPlacement: boolean
setShouldSeeLogicalDisengage: () => void
isWaitingForResumeOperation: boolean
setIsWaitingForResumeOperation: () => void
}

export function EstopPressedModal({
isEngaged,
closeModal,
isDismissedModal,
setIsDismissedModal,
isWaitingForLogicalDisengage,
isWaitingForPlateReaderLidPlacement,
setShouldSeeLogicalDisengage,
isWaitingForResumeOperation,
setIsWaitingForResumeOperation,
}: EstopPressedModalProps): JSX.Element {
const isOnDevice = useSelector(getIsOnDevice)
return createPortal(
isOnDevice ? (
<TouchscreenModal
isEngaged={isEngaged}
closeModal={closeModal}
isWaitingForLogicalDisengage={isWaitingForLogicalDisengage}
isWaitingForPlateReaderLidPlacement={
isWaitingForPlateReaderLidPlacement
}
setShouldSeeLogicalDisengage={setShouldSeeLogicalDisengage}
isWaitingForResumeOperation={isWaitingForResumeOperation}
setIsWaitingForResumeOperation={setIsWaitingForResumeOperation}
/>
) : (
<>
{isDismissedModal === false ? (
<DesktopModal
isEngaged={isEngaged}
closeModal={closeModal}
setIsDismissedModal={setIsDismissedModal}
isWaitingForLogicalDisengage={isWaitingForLogicalDisengage}
isWaitingForPlateReaderLidPlacement={
isWaitingForPlateReaderLidPlacement
}
setShouldSeeLogicalDisengage={setShouldSeeLogicalDisengage}
/>
) : null}
<DesktopModal
isEngaged={isEngaged}
closeModal={closeModal}
isWaitingForResumeOperation={isWaitingForResumeOperation}
setIsWaitingForResumeOperation={setIsWaitingForResumeOperation}
/>
</>
),
getTopPortalEl()
Expand All @@ -92,16 +77,18 @@ export function EstopPressedModal({
function TouchscreenModal({
isEngaged,
closeModal,
isWaitingForLogicalDisengage,
isWaitingForPlateReaderLidPlacement,
setShouldSeeLogicalDisengage,
isWaitingForResumeOperation,
setIsWaitingForResumeOperation,
}: EstopPressedModalProps): JSX.Element {
const { t } = useTranslation(['device_settings', 'branded'])
const [isResuming, setIsResuming] = React.useState<boolean>(false)
const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation()

const { handlePlaceReaderLid, isPlacing } = usePlacePlateReaderLid({
onSettled: undefined,
const {
handlePlaceReaderLid,
isValidPlateReaderMove,
} = usePlacePlateReaderLid({
onSettled: closeModal,
})
const modalHeader: OddModalHeaderBaseProps = {
title: t('estop_pressed'),
Expand All @@ -114,10 +101,12 @@ function TouchscreenModal({
}
const handleClick = (): void => {
setIsResuming(true)
setIsWaitingForResumeOperation()
acknowledgeEstopDisengage(null)
setShouldSeeLogicalDisengage()
handlePlaceReaderLid()
closeModal()
if (!isValidPlateReaderMove) {
closeModal()
}
}
return (
<OddModal {...modalProps}>
Expand Down Expand Up @@ -146,29 +135,13 @@ function TouchscreenModal({
data-testid="Estop_pressed_button"
width="100%"
iconName={
isResuming ||
isPlacing ||
isWaitingForLogicalDisengage ||
isWaitingForPlateReaderLidPlacement
? 'ot-spinner'
: undefined
isResuming || isWaitingForResumeOperation ? 'ot-spinner' : undefined
}
iconPlacement={
isResuming ||
isPlacing ||
isWaitingForLogicalDisengage ||
isWaitingForPlateReaderLidPlacement
? 'startIcon'
: undefined
isResuming || isWaitingForResumeOperation ? 'startIcon' : undefined
}
buttonText={t('resume_robot_operations')}
disabled={
isEngaged ||
isResuming ||
isPlacing ||
isWaitingForLogicalDisengage ||
isWaitingForPlateReaderLidPlacement
}
disabled={isEngaged || isResuming || isWaitingForResumeOperation}
onClick={handleClick}
/>
</Flex>
Expand All @@ -179,29 +152,23 @@ function TouchscreenModal({
function DesktopModal({
isEngaged,
closeModal,
setIsDismissedModal,
isWaitingForLogicalDisengage,
isWaitingForPlateReaderLidPlacement,
setShouldSeeLogicalDisengage,
isWaitingForResumeOperation,
setIsWaitingForResumeOperation,
}: EstopPressedModalProps): JSX.Element {
const { t } = useTranslation('device_settings')
const [isResuming, setIsResuming] = React.useState<boolean>(false)
const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation()
const { placeReaderLid, isPlacing } = usePlacePlateReaderLid({
pipetteInfo: null,
const {
handlePlaceReaderLid,
isValidPlateReaderMove,
} = usePlacePlateReaderLid({
onSettled: closeModal,
})

const handleCloseModal = (): void => {
if (setIsDismissedModal != null) {
setIsDismissedModal(true)
}
closeModal()
}

const modalProps: ModalProps = {
type: 'error',
title: t('estop_pressed'),
onClose: handleCloseModal,
onClose: closeModal,
closeOnOutsideClick: false,
childrenPadding: SPACING.spacing24,
width: '47rem',
Expand All @@ -210,20 +177,12 @@ function DesktopModal({
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (e): void => {
e.preventDefault()
setIsResuming(true)
acknowledgeEstopDisengage(
{},
{
onSuccess: () => {
setShouldSeeLogicalDisengage()
placeReaderLid()
closeModal()
},
onError: (error: any) => {
setIsResuming(false)
console.error(error)
},
}
)
setIsWaitingForResumeOperation()
acknowledgeEstopDisengage(null)
handlePlaceReaderLid()
if (!isValidPlateReaderMove) {
closeModal()
}
}

return (
Expand All @@ -238,23 +197,14 @@ function DesktopModal({
<Flex justifyContent={JUSTIFY_FLEX_END}>
<PrimaryButton
onClick={handleClick}
disabled={
isEngaged ||
isPlacing ||
isResuming ||
isWaitingForLogicalDisengage ||
isWaitingForPlateReaderLidPlacement
}
disabled={isEngaged || isResuming || isWaitingForResumeOperation}
>
<Flex
flexDirection={DIRECTION_ROW}
gridGap={SPACING.spacing8}
alignItems={ALIGN_CENTER}
>
{isResuming ||
isPlacing ||
isWaitingForLogicalDisengage ||
isWaitingForPlateReaderLidPlacement ? (
{isResuming || isWaitingForResumeOperation ? (
<Icon size="1rem" spin name="ot-spinner" />
) : null}
{t('resume_robot_operations')}
Expand Down
95 changes: 36 additions & 59 deletions app/src/organisms/EmergencyStop/EstopTakeover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ import { useEstopQuery } from '@opentrons/react-api-client'

import { EstopPressedModal } from './EstopPressedModal'
import { EstopMissingModal } from './EstopMissingModal'
import { useEstopContext } from './hooks'
import { useIsUnboxingFlowOngoing } from '/app/redux-resources/config'
import { getLocalRobot } from '/app/redux/discovery'
import {
PHYSICALLY_ENGAGED,
LOGICALLY_ENGAGED,
NOT_PRESENT,
DISENGAGED,
} from './constants'
import { PHYSICALLY_ENGAGED, NOT_PRESENT, DISENGAGED } from './constants'
import { EstopState } from '@opentrons/api-client'

Check failure on line 10 in app/src/organisms/EmergencyStop/EstopTakeover.tsx

View workflow job for this annotation

GitHub Actions / js checks

All imports in the declaration are only used as types. Use `import type`

Check failure on line 10 in app/src/organisms/EmergencyStop/EstopTakeover.tsx

View workflow job for this annotation

GitHub Actions / js checks

All imports in the declaration are only used as types. Use `import type`

const ESTOP_CURRENTLY_DISENGAGED_REFETCH_INTERVAL_MS = 10000
const ESTOP_CURRENTLY_ENGAGED_REFETCH_INTERVAL_MS = 1000
Expand All @@ -22,78 +17,60 @@ interface EstopTakeoverProps {
}

export function EstopTakeover({ robotName }: EstopTakeoverProps): JSX.Element {
const [estopEngaged, setEstopEngaged] = useState<boolean>(false)
const [isDismissedModal, setIsDismissedModal] = useState<boolean>(false)
const [
isWaitingForLogicalDisengage,
setIsWaitingForLogicalDisengage,
isWaitingForResumeOperation,
setIsWatingForResumeOperation,
] = useState<boolean>(false)
const [
isWaitingForPlateReaderLidPlacement,
setisWaitingForPlateReaderLidPlacement,
] = useState<boolean>(false)
const { data: estopStatus } = useEstopQuery({
refetchInterval: estopEngaged

const [estopState, setEstopState] = useState<EstopState>(DISENGAGED)
const [showEmergencyStopModal, setShowEmergencyStopModal] = useState<boolean>(
false
)

// TODO: (ba, 2024-10-24): Use notifications instead of polling
useEstopQuery({
refetchInterval: showEmergencyStopModal
? ESTOP_CURRENTLY_ENGAGED_REFETCH_INTERVAL_MS
: ESTOP_CURRENTLY_DISENGAGED_REFETCH_INTERVAL_MS,
onSuccess: response => {
setEstopEngaged(
[PHYSICALLY_ENGAGED || LOGICALLY_ENGAGED].includes(
response?.data.status
)
setEstopState(response?.data.status)
setShowEmergencyStopModal(
response.data.status !== DISENGAGED || isWaitingForResumeOperation
)
setIsWaitingForLogicalDisengage(false)
},
})

const {
isEmergencyStopModalDismissed,
setIsEmergencyStopModalDismissed,
} = useEstopContext()
const isUnboxingFlowOngoing = useIsUnboxingFlowOngoing()
const closeModal = (): void => {
if (estopStatus?.data.status === DISENGAGED) {
setIsEmergencyStopModalDismissed(false)
}
setIsWatingForResumeOperation(false)
}
const localRobot = useSelector(getLocalRobot)
const localRobotName = localRobot?.name ?? 'no name'

const TargetEstopModal = (): JSX.Element | null => {
switch (estopStatus?.data.status) {
case PHYSICALLY_ENGAGED:
case LOGICALLY_ENGAGED:
return (
<EstopPressedModal
isEngaged={estopStatus?.data.status === PHYSICALLY_ENGAGED}
closeModal={closeModal}
isDismissedModal={isEmergencyStopModalDismissed}
setIsDismissedModal={setIsEmergencyStopModalDismissed}
isWaitingForLogicalDisengage={isWaitingForLogicalDisengage}
isWaitingForPlateReaderLidPlacement={
isWaitingForPlateReaderLidPlacement
}
setShouldSeeLogicalDisengage={() => {
setIsWaitingForLogicalDisengage(true)
}}
/>
)
case NOT_PRESENT:
return (
<EstopMissingModal
robotName={robotName != null ? robotName : localRobotName}
closeModal={closeModal}
isDismissedModal={isEmergencyStopModalDismissed}
setIsDismissedModal={setIsEmergencyStopModalDismissed}
/>
)
default:
return null
}
return estopState === NOT_PRESENT ? (
<EstopMissingModal
robotName={robotName != null ? robotName : localRobotName}
closeModal={closeModal}
isDismissedModal={isDismissedModal}
setIsDismissedModal={setIsDismissedModal}
/>
) : estopState !== DISENGAGED || isWaitingForResumeOperation ? (
<EstopPressedModal
isEngaged={estopState === PHYSICALLY_ENGAGED}
closeModal={closeModal}
isWaitingForResumeOperation={isWaitingForResumeOperation}
setIsWaitingForResumeOperation={() => {
setIsWatingForResumeOperation(true)
}}
/>
) : null
}

return (
<>
{estopStatus?.data.status !== DISENGAGED && !isUnboxingFlowOngoing ? (
{showEmergencyStopModal && !isUnboxingFlowOngoing ? (
<TargetEstopModal />
) : null}
</>
Expand Down
9 changes: 7 additions & 2 deletions app/src/resources/modules/hooks/usePlacePlateReaderLid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { useRobotControlCommands } from '/app/resources/maintenance_runs'

interface UsePlacePlateReaderLidResult {
handlePlaceReaderLid: () => Promise<void>
isPlacing: boolean
isExecuting: boolean
isValidPlateReaderMove: boolean
}

type UsePlacePlateReaderLidProps = Pick<
Expand Down Expand Up @@ -55,7 +56,11 @@ export function usePlacePlateReaderLid(
}
}

return { handlePlaceReaderLid, isPlacing: isExecuting }
return {
handlePlaceReaderLid,
isExecuting: isExecuting,
isValidPlateReaderMove,
}
}

const buildLoadModuleCommand = (location: ModuleLocation): CreateCommand => {
Expand Down

0 comments on commit de39cbe

Please sign in to comment.