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(protocol-designer): editing labware on top of a module and adapter fixes #17161

Merged
merged 7 commits into from
Dec 20, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,6 @@
"volume_per_well": "Volume per well",
"well_name": "Well {{wellName}}",
"well_order_title": "{{prefix}} well order",
"well_position": "Well position: X {{x}} Y {{y}} Z {{z}} (mm)"
"well_position": "Well position: X {{x}} Y {{y}} Z {{z}} (mm)",
"unknown_module": "Unknown module"
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import {
createDeckFixture,
deleteDeckFixture,
} from '../../../step-forms/actions/additionalItems'
import { createModule, deleteModule } from '../../../step-forms/actions'
import { deleteModule } from '../../../step-forms/actions'
import { getSavedStepForms } from '../../../step-forms/selectors'
import { getDeckSetupForActiveItem } from '../../../top-selectors/labware-locations'
import {
createContainer,
Expand All @@ -50,9 +51,12 @@ import { useBlockingHint } from '../../../organisms/BlockingHintModal/useBlockin
import { selectors } from '../../../labware-ingred/selectors'
import { useKitchen } from '../../../organisms/Kitchen/hooks'
import { getDismissedHints } from '../../../tutorial/selectors'
import { createContainerAboveModule } from '../../../step-forms/actions/thunks'
import { ConfirmDeleteStagingAreaModal } from '../../../organisms'
import {
createContainerAboveModule,
createModuleEntityAndChangeForm,
} from '../../../step-forms/actions/thunks'
import { BUTTON_LINK_STYLE } from '../../../atoms'
import { ConfirmDeleteStagingAreaModal } from '../../../organisms'
import { getSlotInformation } from '../utils'
import { ALL_ORDERED_CATEGORIES, FIXTURES, MOAM_MODELS } from './constants'
import { LabwareTools } from './LabwareTools'
Expand All @@ -63,6 +67,13 @@ import type { AddressableAreaName, ModuleModel } from '@opentrons/shared-data'
import type { ThunkDispatch } from '../../../types'
import type { Fixture } from './constants'

const mapModTypeToStepType: Record<string, string> = {
heaterShakerModuleType: 'heaterShaker',
magneticModuleType: 'magnet',
temperatureModuleType: 'temperature',
thermocyclerModuleType: 'thermocycler',
}

interface DeckSetupToolsProps {
onCloseClick: () => void
setHoveredLabware: (defUri: string | null) => void
Expand All @@ -80,6 +91,7 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null {
const { makeSnackbar } = useKitchen()
const selectedSlotInfo = useSelector(selectors.getZoomedInSlotInfo)
const robotType = useSelector(getRobotType)
const savedSteps = useSelector(getSavedStepForms)
const [showDeleteLabwareModal, setShowDeleteLabwareModal] = useState<
ModuleModel | 'clear' | null
>(null)
Expand Down Expand Up @@ -255,7 +267,11 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null {
if (
createdLabwareForSlot != null &&
(!keepExistingLabware ||
createdLabwareForSlot.labwareDefURI !== selectedLabwareDefUri)
createdLabwareForSlot.labwareDefURI !== selectedLabwareDefUri ||
// if nested labware changes but labware doesn't, still delete both
(createdLabwareForSlot.labwareDefURI === selectedLabwareDefUri &&
createdNestedLabwareForSlot?.labwareDefURI !==
selectedNestedLabwareDefUri))
) {
dispatch(deleteContainer({ labwareId: createdLabwareForSlot.id }))
}
Expand Down Expand Up @@ -309,11 +325,33 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null {
}
if (selectedModuleModel != null) {
// create module
const moduleType = getModuleType(selectedModuleModel)

const moduleSteps = Object.values(savedSteps).filter(step => {
return (
step.stepType === mapModTypeToStepType[moduleType] &&
// only update module steps that match the old moduleId
// to accommodate instances of MoaM
step.moduleId === createdModuleForSlot?.id
)
})

const pauseSteps = Object.values(savedSteps).filter(step => {
return (
step.stepType === 'pause' &&
// only update pause steps that match the old moduleId
// to accommodate instances of MoaM
step.moduleId === createdModuleForSlot?.id
)
})

dispatch(
createModule({
createModuleEntityAndChangeForm({
slot,
type: getModuleType(selectedModuleModel),
type: moduleType,
model: selectedModuleModel,
moduleSteps,
pauseSteps,
})
)
}
Expand Down Expand Up @@ -344,7 +382,11 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null {
if (
selectedModuleModel != null &&
selectedLabwareDefUri != null &&
createdLabwareForSlot?.labwareDefURI !== selectedLabwareDefUri
(createdLabwareForSlot?.labwareDefURI !== selectedLabwareDefUri ||
// if nested labware changes but labware doesn't, still create both both
(createdLabwareForSlot.labwareDefURI === selectedLabwareDefUri &&
createdNestedLabwareForSlot?.labwareDefURI !==
selectedNestedLabwareDefUri))
) {
// create adapter + labware on module
dispatch(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { i18n } from '../../../../assets/localization'
import { renderWithProviders } from '../../../../__testing-utils__'
import { deleteContainer } from '../../../../labware-ingred/actions'
import { deleteModule } from '../../../../step-forms/actions'
import { getSavedStepForms } from '../../../../step-forms/selectors'
import { getRobotType } from '../../../../file-data/selectors'
import { getEnableAbsorbanceReader } from '../../../../feature-flags/selectors'
import { deleteDeckFixture } from '../../../../step-forms/actions/additionalItems'
Expand All @@ -19,7 +20,6 @@ import { getDeckSetupForActiveItem } from '../../../../top-selectors/labware-loc
import { DeckSetupTools } from '../DeckSetupTools'
import { LabwareTools } from '../LabwareTools'

import type * as React from 'react'
import type { LabwareDefinition2 } from '@opentrons/shared-data'

vi.mock('../LabwareTools')
Expand All @@ -31,6 +31,7 @@ vi.mock('../../../../step-forms/actions')
vi.mock('../../../../step-forms/actions/additionalItems')
vi.mock('../../../../labware-ingred/selectors')
vi.mock('../../../../tutorial/selectors')
vi.mock('../../../../step-forms/selectors')
const render = (props: React.ComponentProps<typeof DeckSetupTools>) => {
return renderWithProviders(<DeckSetupTools {...props} />, {
i18nInstance: i18n,
Expand Down Expand Up @@ -65,6 +66,7 @@ describe('DeckSetupTools', () => {
additionalEquipmentOnDeck: {},
pipettes: {},
})
vi.mocked(getSavedStepForms).mockReturnValue({})
vi.mocked(getDismissedHints).mockReturnValue([])
})
afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ interface StepSummaryProps {
export function StepSummary(props: StepSummaryProps): JSX.Element | null {
const { currentStep, stepDetails } = props
const { t } = useTranslation(['protocol_steps', 'application'])
const unknownModule = t('unkonwn_module')
const labwareNicknamesById = useSelector(getLabwareNicknamesById)
const additionalEquipmentEntities = useSelector(
getAdditionalEquipmentEntities
Expand Down Expand Up @@ -124,9 +125,8 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
engageHeight,
magnetAction,
} = currentStep
const magneticModuleDisplayName = getModuleDisplayName(
modules[magneticModuleId].model
)
const magneticModuleDisplayName =
getModuleDisplayName(modules[magneticModuleId]?.model) ?? unknownModule
stepSummaryContent =
magnetAction === 'engage' ? (
<StyledTrans
Expand Down Expand Up @@ -231,9 +231,8 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
)
break
case 'untilTemperature':
const pauseModuleDisplayName = getModuleDisplayName(
modules[pauseModuleId].model
)
const pauseModuleDisplayName =
getModuleDisplayName(modules[pauseModuleId]?.model) ?? unknownModule
stepSummaryContent = (
<StyledTrans
i18nKey="protocol_steps:pause.untilTemperature"
Expand All @@ -259,9 +258,8 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
targetTemperature,
} = currentStep
const isDeactivating = setTemperature === 'false'
const tempModuleDisplayName = getModuleDisplayName(
modules[tempModuleId].model
)
const tempModuleDisplayName =
getModuleDisplayName(modules[tempModuleId]?.model) ?? unknownModule
stepSummaryContent = isDeactivating ? (
<StyledTrans
i18nKey={'protocol_steps:temperature_module.deactivated'}
Expand Down Expand Up @@ -361,9 +359,9 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
targetHeaterShakerTemperature,
targetSpeed,
} = currentStep
const moduleDisplayName = getModuleDisplayName(
modules[heaterShakerModuleId].model
)
const moduleDisplayName =
getModuleDisplayName(modules[heaterShakerModuleId]?.model) ??
unknownModule
stepSummaryContent = (
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing4}>
<Flex gridGap={SPACING.spacing20} alignItems={ALIGN_CENTER}>
Expand Down
55 changes: 54 additions & 1 deletion protocol-designer/src/step-forms/actions/thunks.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { createContainer } from '../../labware-ingred/actions'
import { getDeckSetupForActiveItem } from '../../top-selectors/labware-locations'
import { uuid } from '../../utils'
import { changeSavedStepForm } from '../../steplist/actions'

import type { DeckSlotId } from '@opentrons/shared-data'
import type {
DeckSlotId,
ModuleModel,
ModuleType,
} from '@opentrons/shared-data'
import type { ThunkAction } from '../../types'
import type {
CreateContainerAction,
RenameLabwareAction,
} from '../../labware-ingred/actions'
import type { CreateModuleAction } from './modules'
import type { ChangeSavedStepFormAction } from '../../steplist/actions'
import type { FormData } from '../../form-types'

export interface CreateContainerAboveModuleArgs {
slot: DeckSlotId
Expand Down Expand Up @@ -37,3 +46,47 @@ export const createContainerAboveModule: (
})
)
}

interface ModuleAndChangeFormArgs {
slot: DeckSlotId
type: ModuleType
model: ModuleModel
moduleSteps: FormData[]
pauseSteps: FormData[]
}
export const createModuleEntityAndChangeForm: (
args: ModuleAndChangeFormArgs
) => ThunkAction<CreateModuleAction | ChangeSavedStepFormAction> = args => (
dispatch,
getState
) => {
const { slot, model, type, moduleSteps, pauseSteps } = args
const moduleId = `${uuid()}:${type}`

dispatch({
type: 'CREATE_MODULE',
payload: { slot, model, type, id: moduleId },
})

// if steps are created with the module that has been regenerated, migrate them to use the correct moduleId
moduleSteps.forEach(step => {
dispatch(
changeSavedStepForm({
stepId: step.id,
update: {
moduleId,
},
})
)
})
pauseSteps.forEach(step => {
dispatch(
changeSavedStepForm({
stepId: step.id,
update: {
moduleId,
},
})
)
})
}
Loading