diff --git a/protocol-designer/src/components/StepEditForm/fields/LabwareField.tsx b/protocol-designer/src/components/StepEditForm/fields/LabwareField.tsx index 75756800ac5..582dbf41092 100644 --- a/protocol-designer/src/components/StepEditForm/fields/LabwareField.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/LabwareField.tsx @@ -14,6 +14,5 @@ export const LabwareField = (props: FieldProps): JSX.Element => { props.name === 'dispense_labware' ? [...options, ...disposalOptions] : [...options] - return } diff --git a/protocol-designer/src/components/StepEditForm/fields/MoveLabwareField.tsx b/protocol-designer/src/components/StepEditForm/fields/MoveLabwareField.tsx new file mode 100644 index 00000000000..9ad2c230c0a --- /dev/null +++ b/protocol-designer/src/components/StepEditForm/fields/MoveLabwareField.tsx @@ -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 const MoveLabwareField = (props: FieldProps): JSX.Element => { + const options = useSelector(getMoveLabwareOptions) + return +} diff --git a/protocol-designer/src/components/StepEditForm/fields/StepFormDropdownField.tsx b/protocol-designer/src/components/StepEditForm/fields/StepFormDropdownField.tsx index a311c31c8d8..ccafb78e368 100644 --- a/protocol-designer/src/components/StepEditForm/fields/StepFormDropdownField.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/StepFormDropdownField.tsx @@ -27,7 +27,6 @@ export const StepFormDropdown = (props: StepFormDropdownProps): JSX.Element => { const availableOptionIds = options.map(opt => opt.value) // @ts-expect-error (ce, 2021-06-21) unknown not assignable to string const fieldValue = availableOptionIds.includes(value) ? String(value) : null - return ( { label={t('form:step_edit_form.labwareLabel.movedLabware')} className={styles.large_field} > - + {robotType === FLEX_ROBOT_TYPE ? ( { ]) }) - 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 - 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: { @@ -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' }, ]) }) }) diff --git a/protocol-designer/src/ui/labware/selectors.ts b/protocol-designer/src/ui/labware/selectors.ts index 24790e7174f..119805baa1c 100644 --- a/protocol-designer/src/ui/labware/selectors.ts +++ b/protocol-designer/src/ui/labware/selectors.ts @@ -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 { + AllTemporalPropertiesForTimelineFrame, + SavedStepFormState, +} from '../../step-forms' const TRASH = 'Trash Bin' @@ -35,30 +39,63 @@ export const _sortLabwareDropdownOptions = (options: Options): Options => return a.name.localeCompare(b.name) }) -/** Returns options for labware dropdowns. +const getNickNames = ( + nicknamesById: Record, + 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 = 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 = createSelector( +export const getMoveLabwareOptions: Selector = 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, @@ -73,66 +110,86 @@ export const getLabwareOptions: Selector = createSelector( ) const isAdapter = labwareEntity.def.allowedRoles?.includes('adapter') - const isOffDeck = getLabwareOffDeck( + const nickName = getNickNames( + 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 = 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') + const nickName = getNickNames( + 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) } )