Skip to content

Commit

Permalink
fix(app): disable module calibration if heating or cooling (#15054)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncdiehl11 authored May 3, 2024
1 parent 02a1a16 commit 0526f55
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
1 change: 1 addition & 0 deletions app/src/assets/localization/en/module_wizard_flows.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"location_occupied": "A {{fixture}} is currently specified here on the deck configuration",
"module_calibrating": "Stand back, {{moduleName}} is calibrating",
"module_calibration": "Module calibration",
"module_heating_or_cooling": "Module calibration cannot proceed while heating or cooling",
"module_secured": "The module must be fully secured in its caddy and secured in the deck slot.",
"module_too_hot": "Module is too hot to proceed to module calibration",
"move_gantry_to_front": "Move gantry to front",
Expand Down
42 changes: 38 additions & 4 deletions app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { useTranslation } from 'react-i18next'

import { Flex, POSITION_RELATIVE, useHoverTooltip } from '@opentrons/components'

import { MODULE_MODELS_OT2_ONLY } from '@opentrons/shared-data'
import {
HEATERSHAKER_MODULE_TYPE,
MODULE_MODELS_OT2_ONLY,
TEMPERATURE_MODULE_TYPE,
THERMOCYCLER_MODULE_TYPE,
} from '@opentrons/shared-data'
import { MenuList } from '../../atoms/MenuList'
import { Tooltip } from '../../atoms/Tooltip'
import { MenuItem } from '../../atoms/MenuList/MenuItem'
Expand Down Expand Up @@ -69,6 +74,23 @@ export const ModuleOverflowMenu = (
isDisabled = true
}

let isHeatingOrCooling
switch (module.moduleType) {
case TEMPERATURE_MODULE_TYPE:
isHeatingOrCooling = module.data.status !== 'idle'
break
case HEATERSHAKER_MODULE_TYPE:
isHeatingOrCooling = module.data.temperatureStatus !== 'idle'
break
case THERMOCYCLER_MODULE_TYPE:
isHeatingOrCooling =
module.data.lidTemperatureStatus !== 'idle' ||
module.data.status !== 'idle'
break
default:
isHeatingOrCooling = false
}

const { menuOverflowItemsByModuleType } = useModuleOverflowMenu(
module,
handleAboutClick,
Expand All @@ -79,6 +101,18 @@ export const ModuleOverflowMenu = (
isIncompatibleWithOT3
)

const isCalibrateDisabled = !isPipetteReady || isTooHot || isHeatingOrCooling
let calibrateDisabledReason
if (!isPipetteReady) {
calibrateDisabledReason = t('calibrate_pipette')
} else if (isTooHot) {
calibrateDisabledReason = t('module_too_hot')
} else if (isHeatingOrCooling) {
calibrateDisabledReason = t('module_heating_or_cooling')
} else {
calibrateDisabledReason = null
}

return (
<Flex position={POSITION_RELATIVE}>
<MenuList>
Expand All @@ -89,7 +123,7 @@ export const ModuleOverflowMenu = (
<>
<MenuItem
onClick={handleCalibrateClick}
disabled={!isPipetteReady || isTooHot}
disabled={isCalibrateDisabled}
{...targetProps}
>
{i18n.format(
Expand All @@ -99,9 +133,9 @@ export const ModuleOverflowMenu = (
'capitalize'
)}
</MenuItem>
{!isPipetteReady || isTooHot ? (
{isCalibrateDisabled ? (
<Tooltip tooltipProps={tooltipProps}>
{t(!isPipetteReady ? 'calibrate_pipette' : 'module_too_hot')}
{calibrateDisabledReason}
</Tooltip>
) : null}
</>
Expand Down
40 changes: 40 additions & 0 deletions app/src/organisms/ModuleCard/__tests__/ModuleOverflowMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
import { useCurrentRunId } from '../../ProtocolUpload/hooks'
import { ModuleOverflowMenu } from '../ModuleOverflowMenu'

import type { TemperatureStatus } from '@opentrons/api-client'

vi.mock('../../Devices/hooks')
vi.mock('../../RunTimeControl/hooks')
vi.mock('../../ProtocolUpload/hooks')
Expand Down Expand Up @@ -535,6 +537,44 @@ describe('ModuleOverflowMenu', () => {
expect(calibrate).toBeDisabled()
})

it('renders a disabled calibrate button if module is heating or cooling', () => {
vi.mocked(useIsFlex).mockReturnValue(true)
const mockHeatingModule = {
...mockHeaterShaker,
data: {
...mockHeaterShaker.data,
temperatureStatus: 'heating' as TemperatureStatus,
},
}
props = {
...props,
module: mockHeatingModule,
}
render(props)

const calibrate = screen.getByRole('button', { name: 'Calibrate' })
expect(calibrate).toBeDisabled()
})

it('renders a disabled calibrate button if module temperature status errors', () => {
vi.mocked(useIsFlex).mockReturnValue(true)
const mockHeatingModule = {
...mockHeaterShaker,
data: {
...mockHeaterShaker.data,
temperatureStatus: 'error' as TemperatureStatus,
},
}
props = {
...props,
module: mockHeatingModule,
}
render(props)

const calibrate = screen.getByRole('button', { name: 'Calibrate' })
expect(calibrate).toBeDisabled()
})

it('a mock function should be called when clicking Calibrate if pipette is ready', () => {
vi.mocked(useIsFlex).mockReturnValue(true)
props = {
Expand Down

0 comments on commit 0526f55

Please sign in to comment.