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

fix(app): disable module calibration if heating or cooling #15054

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Loading