Skip to content

Commit

Permalink
fix(protocol-designer): refine logic for auto-placing modules during …
Browse files Browse the repository at this point in the history
…onboarding (#16642)

closes RQA-3389, RQA-3326
  • Loading branch information
jerader authored Nov 1, 2024
1 parent 917f8f2 commit 9dd40b8
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useTranslation } from 'react-i18next'
import without from 'lodash/without'
import { THERMOCYCLER_MODULE_V2 } from '@opentrons/shared-data'
import {
ALIGN_CENTER,
BORDERS,
Expand Down Expand Up @@ -39,13 +38,7 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null {
const additionalEquipment = watch('additionalEquipment')
const modules = watch('modules')
const { t } = useTranslation(['create_new_protocol', 'shared'])
const numSlotsAvailable = getNumSlotsAvailable(modules, additionalEquipment)

const hasTC =
modules != null &&
Object.values(modules).some(
module => module.model === THERMOCYCLER_MODULE_V2
)
const hasTrash = additionalEquipment.some(
ae => ae === 'trashBin' || ae === 'wasteChute'
)
Expand Down Expand Up @@ -87,25 +80,33 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null {
</StyledText>
) : null}
<Flex gridGap={SPACING.spacing4} flexWrap={WRAP}>
{filteredAdditionalEquipment.map(equipment => (
<EmptySelectorButton
disabled={numSlotsAvailable === 0}
key={equipment}
textAlignment={TYPOGRAPHY.textAlignLeft}
iconName="plus"
text={t(`${equipment}`)}
onClick={() => {
if (numSlotsAvailable === 0) {
makeSnackbar(t('slots_limit_reached') as string)
} else {
setValue('additionalEquipment', [
...additionalEquipment,
equipment,
])
}
}}
/>
))}
{filteredAdditionalEquipment.map(equipment => {
const numSlotsAvailable = getNumSlotsAvailable(
modules,
additionalEquipment,
equipment
)

return (
<EmptySelectorButton
disabled={numSlotsAvailable === 0}
key={equipment}
textAlignment={TYPOGRAPHY.textAlignLeft}
iconName="plus"
text={t(`${equipment}`)}
onClick={() => {
if (numSlotsAvailable === 0) {
makeSnackbar(t('slots_limit_reached') as string)
} else {
setValue('additionalEquipment', [
...additionalEquipment,
equipment,
])
}
}}
/>
)
})}
</Flex>
</Flex>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing12}>
Expand All @@ -117,6 +118,11 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null {
const numStagingAreas = filteredAdditionalEquipmentWithoutGripper.filter(
additionalEquipment => additionalEquipment === 'stagingArea'
)?.length
const numSlotsAvailable = getNumSlotsAvailable(
modules,
additionalEquipment,
ae
)

const dropdownProps = {
currentOption: {
Expand All @@ -127,7 +133,7 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null {
filterOptions: getNumOptions(
numSlotsAvailable >= MAX_SLOTS
? MAX_SLOTS
: numSlotsAvailable + numStagingAreas - (hasTC ? 1 : 0)
: numSlotsAvailable + numStagingAreas
),
onClick: (value: string) => {
const inputNum = parseInt(value)
Expand Down
117 changes: 55 additions & 62 deletions protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
getModuleType,
HEATERSHAKER_MODULE_TYPE,
MAGNETIC_BLOCK_TYPE,
MAGNETIC_BLOCK_V1,
TEMPERATURE_MODULE_TYPE,
} from '@opentrons/shared-data'
import { uuid } from '../../utils'
Expand All @@ -43,9 +42,6 @@ import type { ModuleModel, ModuleType } from '@opentrons/shared-data'
import type { FormModule, FormModules } from '../../step-forms'
import type { WizardTileProps } from './types'

const MAX_MAGNETIC_BLOCKS = 4
const MAGNETIC_BLOCKS_ADJUSTMENT = 3

export function SelectModules(props: WizardTileProps): JSX.Element | null {
const { goBack, proceed, watch, setValue } = props
const { t } = useTranslation(['create_new_protocol', 'shared'])
Expand All @@ -59,15 +55,6 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
robotType === FLEX_ROBOT_TYPE
? FLEX_SUPPORTED_MODULE_MODELS
: OT2_SUPPORTED_MODULE_MODELS

const numSlotsAvailable = getNumSlotsAvailable(modules, additionalEquipment)
const hasNoAvailableSlots = numSlotsAvailable === 0
const numMagneticBlocks =
modules != null
? Object.values(modules).filter(
module => module.model === MAGNETIC_BLOCK_V1
)?.length
: 0
const filteredSupportedModules = supportedModules.filter(
moduleModel =>
!(
Expand All @@ -85,7 +72,10 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
MAGNETIC_BLOCK_TYPE,
]

const handleAddModule = (moduleModel: ModuleModel): void => {
const handleAddModule = (
moduleModel: ModuleModel,
hasNoAvailableSlots: boolean
): void => {
if (hasNoAvailableSlots) {
makeSnackbar(t('slots_limit_reached') as string)
} else {
Expand Down Expand Up @@ -120,37 +110,40 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
module: FormModule,
newQuantity: number
): void => {
const moamModules =
modules != null
? Object.entries(modules).filter(
([key, mod]) => mod.type === module.type
)
: []
if (newQuantity > moamModules.length) {
const newModules = { ...modules }
for (let i = 0; i < newQuantity - moamModules.length; i++) {
if (!modules) return

const modulesOfType = Object.entries(modules).filter(
([, mod]) => mod.type === module.type
)
const otherModules = Object.entries(modules).filter(
([, mod]) => mod.type !== module.type
)

if (newQuantity > modulesOfType.length) {
const additionalModules: FormModules = {}
for (let i = 0; i < newQuantity - modulesOfType.length; i++) {
// @ts-expect-error: TS can't determine modules's type correctly
newModules[uuid()] = {
additionalModules[uuid()] = {
model: module.model,
type: module.type,
slot: null,
}
}
setValue('modules', newModules)
} else if (newQuantity < moamModules.length) {
const modulesToRemove = moamModules.length - newQuantity
const remainingModules: FormModules = {}

Object.entries(modules).forEach(([key, mod]) => {
const shouldRemove = moamModules
.slice(-modulesToRemove)
.some(([removeKey]) => removeKey === key)
if (!shouldRemove) {
remainingModules[parseInt(key)] = mod
}
})
const newModules = Object.fromEntries([
...otherModules,
...modulesOfType,
...Object.entries(additionalModules),
])
setValue('modules', newModules)
} else if (newQuantity < modulesOfType.length) {
const modulesToKeep = modulesOfType.slice(0, newQuantity)
const updatedModules = Object.fromEntries([
...otherModules,
...modulesToKeep,
])

setValue('modules', remainingModules)
setValue('modules', updatedModules)
}
}

Expand Down Expand Up @@ -186,26 +179,25 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
? module
: module !== ABSORBANCE_READER_V1
)
.map(moduleModel => (
<EmptySelectorButton
key={moduleModel}
disabled={
(moduleModel !== 'magneticBlockV1' &&
hasNoAvailableSlots) ||
(moduleModel === 'thermocyclerModuleV2' &&
numSlotsAvailable <= 1) ||
(moduleModel === 'magneticBlockV1' &&
hasNoAvailableSlots &&
numMagneticBlocks === MAX_MAGNETIC_BLOCKS)
}
textAlignment={TYPOGRAPHY.textAlignLeft}
iconName="plus"
text={getModuleDisplayName(moduleModel)}
onClick={() => {
handleAddModule(moduleModel)
}}
/>
))}
.map(moduleModel => {
const numSlotsAvailable = getNumSlotsAvailable(
modules,
additionalEquipment,
moduleModel
)
return (
<EmptySelectorButton
key={moduleModel}
disabled={numSlotsAvailable === 0}
textAlignment={TYPOGRAPHY.textAlignLeft}
iconName="plus"
text={getModuleDisplayName(moduleModel)}
onClick={() => {
handleAddModule(moduleModel, numSlotsAvailable === 0)
}}
/>
)
})}
</Flex>
{modules != null && Object.keys(modules).length > 0 ? (
<Flex
Expand Down Expand Up @@ -241,6 +233,11 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
[]
)
.map(module => {
const numSlotsAvailable = getNumSlotsAvailable(
modules,
additionalEquipment,
module.model
)
const dropdownProps = {
currentOption: {
name: `${module.count}`,
Expand All @@ -255,11 +252,7 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null {
},
dropdownType: 'neutral' as DropdownBorder,
filterOptions: getNumOptions(
module.model === 'magneticBlockV1'
? numSlotsAvailable +
MAGNETIC_BLOCKS_ADJUSTMENT +
module.count
: numSlotsAvailable + module.count
numSlotsAvailable + module.count
),
}
return (
Expand Down
Loading

0 comments on commit 9dd40b8

Please sign in to comment.