diff --git a/api/tests/opentrons/conftest.py b/api/tests/opentrons/conftest.py
index 059ef76cc9c..b1d3c7fd28c 100755
--- a/api/tests/opentrons/conftest.py
+++ b/api/tests/opentrons/conftest.py
@@ -795,6 +795,7 @@ def minimal_liquid_class_def1() -> LiquidClassSchemaV1:
return LiquidClassSchemaV1(
liquidClassName="water1",
displayName="water 1",
+ description="some water",
schemaVersion=1,
namespace="test-fixture-1",
byPipette=[],
@@ -806,6 +807,7 @@ def minimal_liquid_class_def2() -> LiquidClassSchemaV1:
return LiquidClassSchemaV1(
liquidClassName="water2",
displayName="water 2",
+ description="some water",
schemaVersion=1,
namespace="test-fixture-2",
byPipette=[
@@ -879,6 +881,7 @@ def maximal_liquid_class_def() -> LiquidClassSchemaV1:
return LiquidClassSchemaV1(
liquidClassName="test_water",
displayName="Test Water",
+ description="some water",
schemaVersion=1,
namespace="opentrons",
byPipette=[
diff --git a/api/tests/opentrons/protocol_api_integration/test_liquid_classes.py b/api/tests/opentrons/protocol_api_integration/test_liquid_classes.py
index cf7791a271a..b372ba6362a 100644
--- a/api/tests/opentrons/protocol_api_integration/test_liquid_classes.py
+++ b/api/tests/opentrons/protocol_api_integration/test_liquid_classes.py
@@ -20,7 +20,7 @@ def test_liquid_class_creation_and_property_fetching(
water = simulated_protocol_context.define_liquid_class("water")
assert water.name == "water"
- assert water.display_name == "Water"
+ assert water.display_name == "Aqueous"
# TODO (spp, 2024-10-17): update this to fetch pipette load name from instrument context
assert (
diff --git a/protocol-designer/src/assets/localization/en/liquids.json b/protocol-designer/src/assets/localization/en/liquids.json
index 0ce974ee765..6c9f50a07dd 100644
--- a/protocol-designer/src/assets/localization/en/liquids.json
+++ b/protocol-designer/src/assets/localization/en/liquids.json
@@ -9,6 +9,7 @@
"delete_liquid": "Delete liquid",
"description": "Description",
"display_color": "Color",
+ "dont_use_liquid_class": "Don't use a liquid class",
"liquid_required": "Liquid required",
"liquid_volume": "Liquid volume by well",
"liquid_volume_nonzero": "Liquid volume must be larger than zero",
@@ -18,6 +19,7 @@
"title": "Liquid class",
"tooltip": "Applies predefined pipetting settings to transfer and mix steps using this liquid"
},
+ "liquid_class_name_description": "{{displayName}} ({{description}})",
"liquids_added": "Liquids added",
"liquids": "Liquids",
"microliters": "µL",
diff --git a/protocol-designer/src/assets/localization/en/protocol_steps.json b/protocol-designer/src/assets/localization/en/protocol_steps.json
index a2eec080f47..efb671b06ea 100644
--- a/protocol-designer/src/assets/localization/en/protocol_steps.json
+++ b/protocol-designer/src/assets/localization/en/protocol_steps.json
@@ -67,7 +67,10 @@
"distribute": "Distributingfrom{{sourceWells}} of {{source}}to{{destinationWells}} of {{destination}}",
"transfer": "Transferringfrom{{sourceWells}} of {{source}}to{{destinationWells}} of {{destination}}",
"consolidate_disposal": "Consolidatingfrom{{sourceWells}} of {{source}}to{{destination}}",
- "transfer_disposal": "Transferringfrom{{sourceWells}} of {{source}}to{{destination}}"
+ "transfer_disposal": "Transferringfrom{{sourceWells}} of {{source}}to{{destination}}",
+ "substeps": {
+ "multi": "Multi"
+ }
},
"multi_dispense_options": "Disposal volume",
"multiAspirate": "Consolidate path",
diff --git a/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx b/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx
index 75ac02ca873..0d659a89da1 100644
--- a/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx
+++ b/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx
@@ -135,12 +135,25 @@ export function DefineLiquidsModal(
}
const liquidClassOptions = [
- { name: 'Choose an option', value: '' },
- ...Object.entries(liquidClassDefs).map(
- ([liquidClassDefName, { displayName }]) => {
- return { name: displayName, value: liquidClassDefName }
- }
- ),
+ { name: t('liquids:dont_use_liquid_class'), value: '' },
+ ...Object.entries(liquidClassDefs)
+ .sort(([_0, a], [_1, b]) => {
+ if (a.displayName < b.displayName) {
+ return -1
+ } else if (a.displayName > b.displayName) {
+ return 1
+ }
+ return 0
+ })
+ .map(([liquidClassDefName, { displayName, description }]) => {
+ return {
+ value: liquidClassDefName,
+ name: t('liquids:liquid_class_name_description', {
+ displayName,
+ description,
+ }),
+ }
+ }),
]
return (
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/PipetteField.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/PipetteField.tsx
index 1f9053b0478..d52d8260e06 100644
--- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/PipetteField.tsx
+++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/PipetteFields/PipetteField.tsx
@@ -14,6 +14,7 @@ export const PipetteField = (props: FieldProps): JSX.Element => {
options={pipetteOptions}
value={value ? String(value) : null}
title={t('pipette')}
+ width="100%"
/>
)
}
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/MultichannelSubstep.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/MultichannelSubstep.tsx
index a57d340445d..b4a7328a539 100644
--- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/MultichannelSubstep.tsx
+++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/MultichannelSubstep.tsx
@@ -1,15 +1,16 @@
import { useState } from 'react'
-import { useTranslation } from 'react-i18next'
+import { Trans, useTranslation } from 'react-i18next'
import {
ALIGN_CENTER,
DIRECTION_COLUMN,
DeckInfoLabel,
Flex,
- JUSTIFY_SPACE_BETWEEN,
ListButton,
+ NO_WRAP,
SPACING,
StyledText,
Tag,
+ WRAP,
} from '@opentrons/components'
import { Substep } from './Substep'
import { formatVolume } from './utils'
@@ -18,6 +19,7 @@ import type {
StepItemSourceDestRow,
SubstepIdentifier,
} from '../../../../steplist'
+import { values } from 'lodash'
interface MultichannelSubstepProps {
trashName: AdditionalEquipmentName | null
@@ -57,6 +59,43 @@ export function MultichannelSubstep(
firstChannelDest ? firstChannelDest.well ?? 'Trash' : ''
}:${lastChannelDest ? lastChannelDest.well : ''}`
+ interface MultiChannelSubstepButtonProps {
+ tagText: string
+ sources: JSX.Element | null
+ destinations: JSX.Element | null
+ }
+
+ function MultiChannelSubstepButton(
+ props: MultiChannelSubstepButtonProps
+ ): JSX.Element {
+ const { tagText, sources, destinations } = props
+ const { t } = useTranslation('protocol_steps')
+ return (
+
+
+ ),
+ tag: ,
+ label1: sources ?? <>>,
+ label2: destinations ?? <>>,
+ }}
+ values={values}
+ />
+
+ )
+ }
+
return (
{/* TODO: need to update this to match designs! */}
-
+
-
- Multi
- {firstChannelSource != null ? (
-
- ) : null}
-
- {firstChannelDest != null ? (
-
- ) : null}
-
-
- {!collapsed &&
- rowGroup.map((row, rowKey) => {
+ {/* replace below Flex with custom component */}
+
+ ) : null
+ }
+ destinations={
+ firstChannelDest != null ? (
+
+ ) : null
+ }
+ />
+ {!collapsed ? (
+
+ {rowGroup.map((row, rowKey) => {
return (
)
})}
-
+
+ ) : null}
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubStepsToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubStepsToolbox.tsx
index a7e272c3623..5bdda7791ec 100644
--- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubStepsToolbox.tsx
+++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubStepsToolbox.tsx
@@ -1,7 +1,6 @@
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import {
- FLEX_MAX_CONTENT,
Flex,
Icon,
PrimaryButton,
@@ -59,7 +58,7 @@ export function SubStepsToolbox(
substeps.substepType === THERMOCYCLER_PROFILE ? (
}
onCloseClick={handleClose}
confirmButton={
diff --git a/shared-data/js/liquidClasses.ts b/shared-data/js/liquidClasses.ts
index d97db8afa47..ac598312e42 100644
--- a/shared-data/js/liquidClasses.ts
+++ b/shared-data/js/liquidClasses.ts
@@ -1,8 +1,12 @@
+import ethanol80V1Uncasted from '../liquid-class/definitions/1/ethanol_80.json'
+import glycerol50V1Uncasted from '../liquid-class/definitions/1/glycerol_50.json'
import waterV1Uncasted from '../liquid-class/definitions/1/water.json'
import type { LiquidClass } from '.'
+const ethanol80V1 = ethanol80V1Uncasted as LiquidClass
+const glycerol50V1 = glycerol50V1Uncasted as LiquidClass
const waterV1 = waterV1Uncasted as LiquidClass
-const defs = { waterV1 }
+const defs = { ethanol80V1, glycerol50V1, waterV1 }
export const getAllLiquidClassDefs = (): Record => defs
diff --git a/shared-data/js/types.ts b/shared-data/js/types.ts
index 3a4152dc442..9e2ad86299f 100644
--- a/shared-data/js/types.ts
+++ b/shared-data/js/types.ts
@@ -798,6 +798,7 @@ interface ByPipetteSetting {
export interface LiquidClass {
liquidClassName: string
displayName: string
+ description: string
schemaVersion: number
namespace: string
byPipette: ByPipetteSetting[]
diff --git a/shared-data/liquid-class/definitions/1/ethanol_80.json b/shared-data/liquid-class/definitions/1/ethanol_80.json
index 3b9870c59b1..b5b978bb637 100644
--- a/shared-data/liquid-class/definitions/1/ethanol_80.json
+++ b/shared-data/liquid-class/definitions/1/ethanol_80.json
@@ -1,6 +1,7 @@
{
"liquidClassName": "ethanol_80",
- "displayName": "Ethanol-80",
+ "displayName": "Volatile",
+ "description": "80% ethanol",
"schemaVersion": 1,
"namespace": "opentrons",
"byPipette": [
diff --git a/shared-data/liquid-class/definitions/1/glycerol_50.json b/shared-data/liquid-class/definitions/1/glycerol_50.json
index 52cf57ff184..a61d14952b7 100644
--- a/shared-data/liquid-class/definitions/1/glycerol_50.json
+++ b/shared-data/liquid-class/definitions/1/glycerol_50.json
@@ -1,6 +1,7 @@
{
"liquidClassName": "glycerol_50",
- "displayName": "Glycerol-50",
+ "displayName": "Viscous",
+ "description": "50% glycerol",
"schemaVersion": 1,
"namespace": "opentrons",
"byPipette": [
diff --git a/shared-data/liquid-class/definitions/1/water.json b/shared-data/liquid-class/definitions/1/water.json
index d7bcd1afdc3..aeea73e7b6f 100644
--- a/shared-data/liquid-class/definitions/1/water.json
+++ b/shared-data/liquid-class/definitions/1/water.json
@@ -1,6 +1,7 @@
{
"liquidClassName": "water",
- "displayName": "Water",
+ "displayName": "Aqueous",
+ "description": "Deionized water",
"schemaVersion": 1,
"namespace": "opentrons",
"byPipette": [
diff --git a/shared-data/liquid-class/fixtures/1/fixture_glycerol50.json b/shared-data/liquid-class/fixtures/1/fixture_glycerol50.json
index 9c24a40452d..1d8b9cef49f 100644
--- a/shared-data/liquid-class/fixtures/1/fixture_glycerol50.json
+++ b/shared-data/liquid-class/fixtures/1/fixture_glycerol50.json
@@ -1,6 +1,7 @@
{
"liquidClassName": "fixture_glycerol50",
- "displayName": "Glycerol 50%",
+ "displayName": "Viscous",
+ "description": "50% glycerol",
"schemaVersion": 1,
"namespace": "opentrons",
"byPipette": [
diff --git a/shared-data/liquid-class/schemas/1.json b/shared-data/liquid-class/schemas/1.json
index 633be549d4c..c965c10562d 100644
--- a/shared-data/liquid-class/schemas/1.json
+++ b/shared-data/liquid-class/schemas/1.json
@@ -448,6 +448,10 @@
"type": "string",
"description": "User-readable name of the liquid class."
},
+ "description": {
+ "type": "string",
+ "description": "User-readable description of the liquid class"
+ },
"schemaVersion": {
"description": "Which schema version a liquid class is using",
"type": "number",
@@ -500,6 +504,7 @@
"required": [
"liquidClassName",
"displayName",
+ "description",
"schemaVersion",
"namespace",
"byPipette"
diff --git a/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py b/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py
index aca371d43e6..31fddaad2a1 100644
--- a/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py
+++ b/shared-data/python/opentrons_shared_data/liquid_classes/liquid_class_definition.py
@@ -380,6 +380,9 @@ class LiquidClassSchemaV1(BaseModel):
..., description="The name of the liquid (e.g., water, ethanol, serum)."
)
displayName: str = Field(..., description="User-readable name of the liquid class.")
+ description: str = Field(
+ ..., description="User-readable description of the liquid class"
+ )
schemaVersion: Literal[1] = Field(
..., description="Which schema version a liquid class is using"
)