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

feat(protocol-designer,-shared-data): introduce push out field in PD #17835

Merged
merged 3 commits into from
Mar 20, 2025
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 @@ -226,7 +226,9 @@
"stepName": "transfer",
"stepDetails": "",
"id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5",
"dispense_touchTip_mmfromTop": -2
"dispense_touchTip_mmfromTop": -2,
"pushOut_checkbox": false,
"pushOut_volume": 0
},
"54dc3200-75c7-11ea-b42f-4b64e50f43e5": {
"moduleId": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@
"stepName": "transfer",
"stepDetails": "",
"id": "3961e4c0-75c7-11ea-b42f-4b64e50f43e5",
"dispense_touchTip_mmfromTop": null
"dispense_touchTip_mmfromTop": null,
"pushOut_checkbox": false,
"pushOut_volume": 0
},
"4f4057e0-75c7-11ea-b42f-4b64e50f43e5": {
"engageHeight": "6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@
"stepName": "transfer",
"stepDetails": "",
"id": "f9a294f1-f42b-4cae-893a-592405349d56",
"dispense_touchTip_mmfromTop": null
"dispense_touchTip_mmfromTop": null,
"pushOut_checkbox": true,
"pushOut_volume": 7
},
"5fdb9a12-fab4-42fd-886f-40af107b15d6": {
"aspirate_delay_checkbox": false,
Expand Down
4 changes: 3 additions & 1 deletion protocol-designer/fixtures/protocol/8/doItAllV8.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@
"stepName": "transfer",
"stepDetails": "",
"id": "d2f74144-a7bf-4ba2-aaab-30d70b2b62c7",
"dispense_touchTip_mmfromTop": null
"dispense_touchTip_mmfromTop": null,
"pushOut_checkbox": true,
"pushOut_volume": 7
},
"240a2c96-3db8-4679-bdac-049306b7b9c4": {
"blockIsActive": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@
"stepName": "transfer things",
"stepDetails": "yeah notes",
"id": "e7d36200-92a5-11e9-ac62-1b173f839d9e",
"dispense_touchTip_mmfromTop": null
"dispense_touchTip_mmfromTop": null,
"pushOut_checkbox": false,
"pushOut_volume": 0
},
"18113c80-92a6-11e9-ac62-1b173f839d9e": {
"aspirate_delay_checkbox": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@
"stepName": "transfer",
"stepDetails": "",
"dispense_touchTip_mmfromTop": null,
"id": "292e8b18-f59e-4c63-b0f3-e242bf50094b"
"id": "292e8b18-f59e-4c63-b0f3-e242bf50094b",
"pushOut_checkbox": true,
"pushOut_volume": 2
},
"960c2d3b-9cf9-49b0-ab4c-af4113f6671a": {
"moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@
"stepName": "transfer",
"stepDetails": "",
"dispense_touchTip_mmfromTop": null,
"id": "83a095fa-b649-4105-99d4-177f1a3f363a"
"id": "83a095fa-b649-4105-99d4-177f1a3f363a",
"pushOut_checkbox": true,
"pushOut_volume": 7
},
"f5ea3139-1585-4848-9d5f-832eb88c99ca": {
"aspirate_airGap_checkbox": false,
Expand Down Expand Up @@ -229,7 +231,9 @@
"stepName": "transfer",
"stepDetails": "",
"dispense_touchTip_mmfromTop": null,
"id": "f5ea3139-1585-4848-9d5f-832eb88c99ca"
"id": "f5ea3139-1585-4848-9d5f-832eb88c99ca",
"pushOut_checkbox": true,
"pushOut_volume": 7
}
},
"orderedStepIds": [
Expand Down
7 changes: 7 additions & 0 deletions protocol-designer/src/assets/localization/en/form.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@
"preWetTip": {
"label": "pre-wet tip"
},
"pushOut": {
"pushOut_volume": {
"caption": "Valid range between {{min}}-{{max}}µL",
"label": "Push out volume"
},
"title": "Push out"
},
"setTemperature": {
"options": {
"false": "Deactivate module",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"nozzles": "Partial pickup requires a tip rack directly on the deck. Full rack pickup requires the Flex 96 Tip Rack Adapter.",
"pipette": "Select the pipette you want to use",
"preWetTip": "Pre-wet by aspirating and dispensing the total aspiration volume",
"pushOut_checkbox": "Helps ensure all liquid leaves the tip",
"setTemperature": "Select the temperature to set your module to",
"wells": "Select wells",
"volume": "Volume to dispense in each well"
Expand Down
34 changes: 24 additions & 10 deletions protocol-designer/src/load-file/migration/8_5_0.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import floor from 'lodash/floor'
import { getPipetteSpecsV2 } from '@opentrons/shared-data'
import { PROTOCOL_DESIGNER_SOURCE } from '../../constants'
import { swatchColors } from '../../components/organisms/DefineLiquidsModal/swatchColors'
import { getDefaultPushOutVolume } from '../../utils'
import { getMigratedPositionFromTop } from './utils/getMigrationPositionFromTop'
import { getAdditionalEquipmentLocationUpdate } from './utils/getAdditionalEquipmentLocationUpdate'
import { getEquipmentLoadInfoFromCommands } from './utils/getEquipmentLoadInfoFromCommands'
Expand All @@ -22,15 +24,10 @@
liquids,
robot,
} = appData

if (designerApplication == null || designerApplication?.data == null) {
throw Error('The designerApplication key in your file is corrupt.')
}
const savedStepForms = designerApplication.data
?.savedStepForms as DesignerApplicationData['savedStepForms']

const ingredients = designerApplication.data.ingredients

const { savedStepForms, ingredients } = designerApplication.data

Check warning on line 30 in protocol-designer/src/load-file/migration/8_5_0.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/load-file/migration/8_5_0.ts#L30

Added line #L30 was not covered by tests
const migratedIngredients: Ingredients = Object.entries(
ingredients
).reduce<Ingredients>((acc, [id, ingredient]) => {
Expand All @@ -48,6 +45,10 @@
(command): command is LoadLabwareCreateCommand =>
command.commandType === 'loadLabware'
)
const equipmentLoadInfoFromCommands = getEquipmentLoadInfoFromCommands(
commands,
labwareDefinitions
)

Check warning on line 51 in protocol-designer/src/load-file/migration/8_5_0.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/load-file/migration/8_5_0.ts#L48-L51

Added lines #L48 - L51 were not covered by tests

const savedStepsWithUpdatedMoveLiquidFields = Object.values(
savedStepForms
Expand All @@ -74,6 +75,20 @@
dispense_labware as string,
'dispense'
)
const tipRackDef = labwareDefinitions[form.tipRack]
const pipetteName =
equipmentLoadInfoFromCommands.pipettes?.[form.pipette]?.pipetteName ??
null
const pipetteSpecs =
pipetteName != null ? getPipetteSpecsV2(pipetteName) : null
const defaultPushOutVolume =
pipetteSpecs == null
? null
: getDefaultPushOutVolume(
Number(form.volume),
pipetteSpecs,
tipRackDef
)

Check warning on line 91 in protocol-designer/src/load-file/migration/8_5_0.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/load-file/migration/8_5_0.ts#L78-L91

Added lines #L78 - L91 were not covered by tests

return {
...acc,
Expand Down Expand Up @@ -124,6 +139,9 @@
dispense_submerge_position_reference: null,
liquidClassesSupported: liquidClassesSupported ?? false,
liquidClass: null,
pushOut_checkbox:
defaultPushOutVolume != null && defaultPushOutVolume > 0,
pushOut_volume: defaultPushOutVolume,

Check warning on line 144 in protocol-designer/src/load-file/migration/8_5_0.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/load-file/migration/8_5_0.ts#L142-L144

Added lines #L142 - L144 were not covered by tests
},
}
}
Expand Down Expand Up @@ -188,10 +206,6 @@
},
{}
)
const equipmentLoadInfoFromCommands = getEquipmentLoadInfoFromCommands(
commands,
labwareDefinitions
)
return {
...appData,
metadata: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import {
getAdditionalEquipmentEntities,
getLabwareEntities,
getPipetteEntities,
} from '../../../../../../step-forms/selectors'
import { getMaxPushOutVolume } from '../../../../../../utils'
import {
getBlowoutLocationOptionsForForm,
getFormErrorsMappedToField,
Expand Down Expand Up @@ -70,7 +72,7 @@
getAdditionalEquipmentEntities
)
const enableLiquidClasses = useSelector(getEnableLiquidClasses)

const pipetteSpec = useSelector(getPipetteEntities)[formData.pipette]?.spec

Check warning on line 75 in protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx#L75

Added line #L75 was not covered by tests
const addFieldNamePrefix = addPrefix(tab)
const isWasteChuteSelected =
propsForFields.dispense_labware?.value != null
Expand Down Expand Up @@ -147,6 +149,11 @@
]
}

const maxPushoutVolume = getMaxPushOutVolume(
Number(formData.volume),
pipetteSpec
)

Check warning on line 155 in protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx#L152-L155

Added lines #L152 - L155 were not covered by tests

const minXYDimension = isDestinationTrash
? null
: getMinXYDimension(labwares[formData[`${tab}_labware`]]?.def, ['A1'])
Expand Down Expand Up @@ -317,6 +324,38 @@
</Flex>
) : null}
</CheckboxExpandStepFormField>
{tab === 'dispense' ? (
<CheckboxExpandStepFormField
title={i18n.format(
t('form:step_edit_form.field.pushOut.title'),
'capitalize'
)}
checkboxValue={propsForFields.pushOut_checkbox.value}
isChecked={propsForFields.pushOut_checkbox.value === true}
checkboxUpdateValue={propsForFields.pushOut_checkbox.updateValue}
tooltipText={propsForFields.pushOut_checkbox.tooltipContent}

Check warning on line 336 in protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx#L327-L336

Added lines #L327 - L336 were not covered by tests
>
{formData.pushOut_checkbox === true ? (
<InputStepFormField
showTooltip={false}
padding="0"
title={t(
'form:step_edit_form.field.pushOut.pushOut_volume.label'
)}
caption={t(
'form:step_edit_form.field.pushOut.pushOut_volume.caption',
{ min: 0, max: maxPushoutVolume }
)}
{...propsForFields.pushOut_volume}
units={t('application:units.microliter')}
errorToShow={getFormLevelError(
'pushOut_volume',
mappedErrorsToField
)}

Check warning on line 354 in protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx#L338-L354

Added lines #L338 - L354 were not covered by tests
/>
) : null}
</CheckboxExpandStepFormField>
) : null}

Check warning on line 358 in protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLiquidTools/SecondStepsMoveLiquidTools.tsx#L356-L358

Added lines #L356 - L358 were not covered by tests
<CheckboxExpandStepFormField
title={i18n.format(
t('form:step_edit_form.field.delay.label'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ describe('createPresavedStepForm', () => {
disposalVolume_volume: '1',
path: 'single',
preWetTip: false,
pushOut_checkbox: null,
pushOut_volume: null,
stepDetails: '',
stepName: 'transfer',
volume: null,
Expand Down
4 changes: 4 additions & 0 deletions protocol-designer/src/steplist/fieldLevel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,10 @@ const stepFieldHelperMap: Record<StepFieldName, StepFieldHelpers> = {
maskValue: composeMaskers(trimDecimals(1)),
castValue: numberOrNull,
},
pushOut_volume: {
maskValue: composeMaskers(maskToFloat, onlyPositiveNumbers),
castValue: numberOrNull,
},
}
const profileFieldHelperMap: Record<string, StepFieldHelpers> = {
// profile step fields
Expand Down
37 changes: 36 additions & 1 deletion protocol-designer/src/steplist/formLevel/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
THERMOCYCLER_PROFILE,
} from '../../constants'
import { getPipetteCapacity } from '../../pipettes/pipetteData'
import { canPipetteUseLabware } from '../../utils'
import { canPipetteUseLabware, getMaxPushOutVolume } from '../../utils'
import { getWellRatio } from '../utils'
import { getTimeFromForm } from '../utils/getTimeFromForm'

Expand Down Expand Up @@ -423,41 +423,55 @@
showAtForm: false,
showAtField: true,
page: 2,
tab: 'aspirate',
}
const DISPENSE_TOUCH_TIP_SPEED_REQUIRED: FormError = {
title: 'Touch tip speed required',
dependentFields: ['dispense_touchTip_speed'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'dispense',
}
const ASPIRATE_TOUCH_TIP_MM_FROM_EDGE_OUT_OF_RANGE: FormError = {
title: 'Value falls outside of accepted range',
dependentFields: ['aspirate_touchTip_mmFromEdge'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'aspirate',
}
const DISPENSE_TOUCH_TIP_MM_FROM_EDGE_OUT_OF_RANGE: FormError = {
title: 'Value falls outside of accepted range',
dependentFields: ['dispense_touchTip_mmFromEdge'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'dispense',
}
const ASPIRATE_TOUCH_TIP_MM_FROM_EDGE_REQUIRED: FormError = {
title: 'Value required',
dependentFields: ['aspirate_touchTip_mmFromEdge'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'aspirate',
}
const DISPENSE_TOUCH_TIP_MM_FROM_EDGE_REQUIRED: FormError = {
title: 'Value required',
dependentFields: ['dispense_touchTip_mmFromEdge'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'dispense',
}
const PUSH_OUT_VOLUME_REQUIRED: FormError = {
title: 'Push out volume required',
dependentFields: ['pushOut_volume'],
showAtForm: false,
showAtField: true,
page: 2,
tab: 'dispense',
}

export interface HydratedFormData {
Expand Down Expand Up @@ -1073,6 +1087,27 @@
? DISPENSE_TOUCH_TIP_MM_FROM_EDGE_REQUIRED
: null
}
export const pushOutVolumeRequired = (
fields: HydratedFormData
): FormError | null => {
const { pushOut_checkbox, pushOut_volume } = fields
return pushOut_checkbox && !pushOut_volume ? PUSH_OUT_VOLUME_REQUIRED : null
}

Check warning on line 1095 in protocol-designer/src/steplist/formLevel/errors.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/steplist/formLevel/errors.ts#L1091-L1095

Added lines #L1091 - L1095 were not covered by tests
export const pushOutVolumeOutOfRange = (
fields: HydratedFormData
): FormError | null => {
const { pushOut_checkbox, pushOut_volume, pipette, volume } = fields
if (pipette == null) {
return null
}
const maxPushOutVolume = getMaxPushOutVolume(
Number(volume),
(pipette as PipetteEntity).spec
)
return pushOut_checkbox && pushOut_volume > maxPushOutVolume
? PUSH_OUT_VOLUME_REQUIRED
: null
}

Check warning on line 1110 in protocol-designer/src/steplist/formLevel/errors.ts

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/steplist/formLevel/errors.ts#L1097-L1110

Added lines #L1097 - L1110 were not covered by tests

/*******************
** Helpers **
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ export function getDefaultsForStepType(
pickUpTip_wellNames: undefined,
pipette: null,
preWetTip: false,
pushOut_checkbox: null,
pushOut_volume: null,
tipRack: null,
volume: null,
}
Expand Down
4 changes: 4 additions & 0 deletions protocol-designer/src/steplist/formLevel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import {
dispenseTouchTipMmFromEdgeOutOfRange,
aspirateTouchTipMmFromEdgeRequired,
dispenseTouchTipMmFromEdgeRequired,
pushOutVolumeRequired,
pushOutVolumeOutOfRange,
} from './errors'

import {
Expand Down Expand Up @@ -159,6 +161,8 @@ const stepFormHelperMap: Partial<Record<StepType, FormHelpers>> = {
dispenseWellsRequired,
aspirateTouchTipSpeedRequired,
dispenseTouchTipSpeedRequired,
pushOutVolumeRequired,
pushOutVolumeOutOfRange,
aspirateTouchTipMmFromEdgeOutOfRange,
dispenseTouchTipMmFromEdgeOutOfRange,
aspirateTouchTipMmFromEdgeRequired,
Expand Down
Loading
Loading