Skip to content

Commit

Permalink
refactor(protocol-designer): fix dropdown selection for moveLabware (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader authored Mar 20, 2024
1 parent 003582f commit 457fb85
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from 'react'
import { useSelector } from 'react-redux'
import { getMoveLabwareOptions } from '../../../ui/labware/selectors'
import { StepFormDropdown } from './StepFormDropdownField'
import type { FieldProps } from '../types'

export function MoveLabwareField(props: FieldProps): JSX.Element {
const options = useSelector(getMoveLabwareOptions)
return <StepFormDropdown {...props} options={options} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export { DisposalVolumeField } from './DisposalVolumeField'
export { FlowRateField } from './FlowRateField'
export { LabwareField } from './LabwareField'
export { LabwareLocationField } from './LabwareLocationField'
export { MoveLabwareField } from './MoveLabwareField'
export { PathField } from './PathField/PathField'
export { PipetteField } from './PipetteField'
export { ProfileItemRows } from './ProfileItemRows'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import {
useHoverTooltip,
} from '@opentrons/components'
import {
LabwareField,
LabwareLocationField,
CheckboxRowField,
MoveLabwareField,
} from '../../fields'
import styles from '../../StepEditForm.module.css'
import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data'
Expand Down Expand Up @@ -50,7 +50,7 @@ export const MoveLabwareForm = (props: StepFormProps): JSX.Element => {
label={t('form:step_edit_form.labwareLabel.movedLabware')}
className={styles.large_field}
>
<LabwareField {...propsForFields.labware} />
<MoveLabwareField {...propsForFields.labware} />
</FormGroup>
{robotType === FLEX_ROBOT_TYPE ? (
<Flex
Expand Down
35 changes: 1 addition & 34 deletions protocol-designer/src/ui/labware/__tests__/selectors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,39 +177,6 @@ describe('labware selectors', () => {
])
})

it('should return labware options for move labware with tips and trash', () => {
const labwareEntities = {
...tipracks,
...trash,
...otherLabware,
}
const initialDeckSetup = {
labware: labwareEntities,
modules: {},
pipettes: {},
}

const presavedStepForm = {
stepType: 'moveLabware',
}
expect(
// @ts-expect-error(jr, 7/17/23): resultFunc doesn't exist on type Selector<Options>
getLabwareOptions.resultFunc(
labwareEntities,
names,
initialDeckSetup,
presavedStepForm,
{},
{}
)
).toEqual([
{ name: 'Opentrons Tip Rack 10 µL', value: 'tiprack10Id' },
{ name: 'Opentrons Tip Rack 1000 µL', value: 'tiprack100Id' },
{ name: 'Source Plate', value: 'wellPlateId' },
{ name: 'Trash', value: mockTrash },
])
})

it('should return labware options with module prefixes when a labware is on module', () => {
const labware = {
wellPlateId: {
Expand Down Expand Up @@ -345,7 +312,7 @@ describe('labware selectors', () => {
)
).toEqual([
{ name: 'Trash', value: mockTrash },
{ name: 'Well Plate', value: 'wellPlateId' },
{ name: 'Well Plate in Magnetic Module', value: 'wellPlateId' },
])
})
})
Expand Down
173 changes: 116 additions & 57 deletions protocol-designer/src/ui/labware/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { getLabwareOffDeck, getLabwareInColumn4 } from './utils'
import type { LabwareEntity } from '@opentrons/step-generation'
import type { DropdownOption, Options } from '@opentrons/components'
import type { Selector } from '../../types'
import type {
AllTemporalPropertiesForTimelineFrame,
SavedStepFormState,
} from '../../step-forms'

const TRASH = 'Trash Bin'

Expand All @@ -35,30 +39,63 @@ export const _sortLabwareDropdownOptions = (options: Options): Options =>
return a.name.localeCompare(b.name)
})

/** Returns options for labware dropdowns.
const getNickname = (
nicknamesById: Record<string, string>,
initialDeckSetup: AllTemporalPropertiesForTimelineFrame,
labwareId: string,
savedStepForms: SavedStepFormState
): string => {
const isOffDeck = getLabwareOffDeck(
initialDeckSetup,
savedStepForms ?? {},
labwareId
)

const moduleOnDeck = getModuleUnderLabware(
initialDeckSetup,
savedStepForms ?? {},
labwareId
)
const module =
moduleOnDeck != null ? getModuleShortNames(moduleOnDeck.type) : null

const isLabwareInColumn4 = getLabwareInColumn4(
initialDeckSetup,
savedStepForms ?? {},
labwareId
)

let nickName: string = nicknamesById[labwareId]
if (module != null) {
nickName = `${nicknamesById[labwareId]} in ${module}`
} else if (isOffDeck) {
nickName = `${nicknamesById[labwareId]} off-deck`
} else if (isLabwareInColumn4) {
nickName = `${nicknamesById[labwareId]} in staging area slot`
}
return nickName
}

/** Returns options for labware dropdowns for moveLabware.
* Ordered by display name / nickname, but with trash at the bottom.
*/
export const getLabwareOptions: Selector<Options> = createSelector(
export const getMoveLabwareOptions: Selector<Options> = createSelector(
stepFormSelectors.getLabwareEntities,
getLabwareNicknamesById,
stepFormSelectors.getInitialDeckSetup,
stepFormSelectors.getPresavedStepForm,
stepFormSelectors.getSavedStepForms,
stepFormSelectors.getAdditionalEquipmentEntities,
(
labwareEntities,
nicknamesById,
initialDeckSetup,
presavedStepForm,
savedStepForms,
additionalEquipmentEntities
) => {
const moveLabwarePresavedStep = presavedStepForm?.stepType === 'moveLabware'
const wasteChuteLocation = Object.values(additionalEquipmentEntities).find(
aE => aE.name === 'wasteChute'
)?.location

const labwareOptions = reduce(
const moveLabwareOptions = reduce(
labwareEntities,
(
acc: Options,
Expand All @@ -72,67 +109,89 @@ export const getLabwareOptions: Selector<Options> = createSelector(
form.newLocation === wasteChuteLocation
)

const isAdapter = labwareEntity.def.allowedRoles?.includes('adapter')
const isOffDeck = getLabwareOffDeck(
const isAdapter =
labwareEntity.def.allowedRoles?.includes('adapter') ?? false
const nickName = getNickname(
nicknamesById,
initialDeckSetup,
savedStepForms ?? {},
labwareId
labwareId,
savedStepForms
)

const moduleOnDeck = getModuleUnderLabware(
initialDeckSetup,
savedStepForms ?? {},
labwareId
// filter out moving trash, adapters, and labware in
// waste chute for moveLabware
return isAdapter || isLabwareInWasteChute
? acc
: [
...acc,
{
name: nickName,
value: labwareId,
},
]
},
[]
)
return _sortLabwareDropdownOptions(moveLabwareOptions)
}
)

/** Returns options for labware dropdowns for moveLiquids.
* Ordered by display name / nickname, but with trash at the bottom.
*/
export const getLabwareOptions: Selector<Options> = createSelector(
stepFormSelectors.getLabwareEntities,
getLabwareNicknamesById,
stepFormSelectors.getInitialDeckSetup,
stepFormSelectors.getSavedStepForms,
stepFormSelectors.getAdditionalEquipmentEntities,
(
labwareEntities,
nicknamesById,
initialDeckSetup,
savedStepForms,
additionalEquipmentEntities
) => {
const wasteChuteLocation = Object.values(additionalEquipmentEntities).find(
aE => aE.name === 'wasteChute'
)?.location
const labwareOptions = reduce(
labwareEntities,
(
acc: Options,
labwareEntity: LabwareEntity,
labwareId: string
): Options => {
const isLabwareInWasteChute = Object.values(savedStepForms).find(
form =>
form.stepType === 'moveLabware' &&
form.labware === labwareId &&
form.newLocation === wasteChuteLocation
)
const module =
moduleOnDeck != null ? getModuleShortNames(moduleOnDeck.type) : null

const isLabwareInColumn4 = getLabwareInColumn4(
const isAdapter =
labwareEntity.def.allowedRoles?.includes('adapter') ?? false
const nickName = getNickname(
nicknamesById,
initialDeckSetup,
savedStepForms ?? {},
labwareId
labwareId,
savedStepForms
)

let nickName = nicknamesById[labwareId]
if (module != null) {
nickName = `${nicknamesById[labwareId]} in ${module}`
} else if (isOffDeck) {
nickName = `${nicknamesById[labwareId]} off-deck`
} else if (isLabwareInColumn4) {
nickName = `${nicknamesById[labwareId]} in staging area slot`
}

if (!moveLabwarePresavedStep) {
// filter out tip racks, adapters, and labware in waste chute
// for aspirating/dispensing/mixing into
return getIsTiprack(labwareEntity.def) ||
isAdapter ||
isLabwareInWasteChute
? acc
: [
...acc,
{
name: nickName,
value: labwareId,
},
]
} else {
// filter out moving trash, adapters, and labware in
// waste chute for moveLabware
return isAdapter || isLabwareInWasteChute
? acc
: [
...acc,
{
name: nickName,
value: labwareId,
},
]
}
return getIsTiprack(labwareEntity.def) ||
isAdapter ||
isLabwareInWasteChute
? acc
: [
...acc,
{
name: nickName,
value: labwareId,
},
]
},
[]
)

return _sortLabwareDropdownOptions(labwareOptions)
}
)
Expand Down

0 comments on commit 457fb85

Please sign in to comment.