From 65e125ec4d7bd74fb2fea96d433222a04e1829de Mon Sep 17 00:00:00 2001 From: koji Date: Wed, 29 Jan 2025 14:54:01 -0500 Subject: [PATCH 01/18] fix(protocol-designer): modify tiprack status check for deselecting (#17377) * fix(protocol-designer): modify tiprack status check for deselecting --- .../src/pages/CreateNewProtocolWizard/SelectPipettes.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx index b9b3153f5fc..f6bb0ea2481 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx @@ -115,8 +115,10 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { (page === 'add' && pipettesByMount[mount].tiprackDefURI == null && noPipette) || - (pipettesByMount.left.tiprackDefURI == null && - pipettesByMount.right.tiprackDefURI == null) + ((pipettesByMount.left.tiprackDefURI == null || + pipettesByMount.left.tiprackDefURI.length === 0) && + (pipettesByMount.right.tiprackDefURI == null || + pipettesByMount.right.tiprackDefURI.length === 0)) const targetPipetteMount = pipettesByMount.left.pipetteName == null || From 42dc7bf4e9e7324bcc642628a1a26c810744ad45 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:36:20 -0500 Subject: [PATCH 02/18] fix(protocol-designer): filter trashbins from move labware new location (#17380) This PR fixes a bug where a user can select a slot occupied by a trash bin as the new location for a move labware step. The user should be prevented from moving labware to a trash bin for Flex and OT-2. Closes RQA-3902 --- .../src/top-selectors/labware-locations/index.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/protocol-designer/src/top-selectors/labware-locations/index.ts b/protocol-designer/src/top-selectors/labware-locations/index.ts index b1104dba6f5..a3845bb8e8f 100644 --- a/protocol-designer/src/top-selectors/labware-locations/index.ts +++ b/protocol-designer/src/top-selectors/labware-locations/index.ts @@ -128,6 +128,13 @@ export const getUnoccupiedLabwareLocationOptions: Selector< if (robotState == null) return null + const trashCutouts = Object.values(additionalEquipmentEntities).reduce< + string[] + >( + (acc, { name, location }) => + name === 'trashBin' && location != null ? [...acc, location] : acc, + [] + ) const { modules, labware } = robotState const slotIdsOccupiedByModules = Object.entries(modules).reduce( (acc, [modId, modOnDeck]) => { @@ -233,6 +240,7 @@ export const getUnoccupiedLabwareLocationOptions: Selector< .map(lw => lw.slot) .includes(slotId) && !isTrashSlot && + !trashCutouts.some(cutout => cutout.includes(slotId)) && !WASTE_CHUTE_ADDRESSABLE_AREAS.includes(slotId) && !notSelectedStagingAreaAddressableAreas.includes(slotId) && !FLEX_MODULE_ADDRESSABLE_AREAS.includes(slotId) && From 890ab23574318772fb6f3690534be149c7b17e4f Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:15:48 -0500 Subject: [PATCH 03/18] fix(step-generation): properly update robotState when dispense is after airGap (#17392) closes RQA-3913 When `airGapinplace` was implemented, i incorrectly got rid of the `dispense` `meta: isAirGap` information. This resulted in the `robotState` liquid state incorrectly getting updated for dispense after `airGapInPlace`. This PR adds the dispense `meta: isAirGap` back, purely for the robot state purposes. Otherwise, i was not sure how to not update the dispense robot state. --- protocol-designer/src/steplist/substepTimeline.ts | 5 ----- .../src/steplist/test/generateSubsteps.test.ts | 8 -------- step-generation/src/__tests__/transfer.test.ts | 10 +++++++++- step-generation/src/commandCreators/atomic/aspirate.ts | 1 - step-generation/src/commandCreators/atomic/dispense.ts | 3 +++ .../src/commandCreators/compound/distribute.ts | 1 + .../src/commandCreators/compound/transfer.ts | 1 + step-generation/src/fixtures/commandFixtures.ts | 2 ++ step-generation/src/fixtures/data.ts | 2 +- .../src/getNextRobotStateAndWarnings/index.ts | 6 +----- 10 files changed, 18 insertions(+), 21 deletions(-) diff --git a/protocol-designer/src/steplist/substepTimeline.ts b/protocol-designer/src/steplist/substepTimeline.ts index 0788acbde6f..638ec97d186 100644 --- a/protocol-designer/src/steplist/substepTimeline.ts +++ b/protocol-designer/src/steplist/substepTimeline.ts @@ -66,9 +66,6 @@ const _createNextTimelineFrame = (args: { volume: args.volume, activeTips: _getNewActiveTips(args.nextFrame.commands.slice(0, args.index)), } - const command = args.command - const isAirGapCommand = - 'meta' in command && command.meta != null && 'isAirGap' in command.meta const newTimelineFrame = args.command.commandType === 'aspirate' || @@ -76,12 +73,10 @@ const _createNextTimelineFrame = (args: { ? { ..._newTimelineFrameKeys, source: args.wellInfo, - isAirGap: isAirGapCommand, } : { ..._newTimelineFrameKeys, dest: args.wellInfo, - isAirGap: isAirGapCommand, } return newTimelineFrame } diff --git a/protocol-designer/src/steplist/test/generateSubsteps.test.ts b/protocol-designer/src/steplist/test/generateSubsteps.test.ts index 86bc5a7ad11..5b110a9d27d 100644 --- a/protocol-designer/src/steplist/test/generateSubsteps.test.ts +++ b/protocol-designer/src/steplist/test/generateSubsteps.test.ts @@ -201,7 +201,6 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'C1', }, - isAirGap: false, }, ], }, @@ -240,7 +239,6 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A1', }, - isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -295,7 +293,6 @@ describe('generateSubstepItem', () => { labwareId: tiprackId, wellName: 'A1', }, - isAirGap: false, source: { well: 'A1', preIngreds: {}, postIngreds: {} }, dest: { well: 'A1', @@ -316,7 +313,6 @@ describe('generateSubstepItem', () => { labwareId: tiprackId, wellName: 'A1', }, - isAirGap: false, dest: { postIngreds: { __air__: { @@ -407,7 +403,6 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A1', }, - isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -434,7 +429,6 @@ describe('generateSubstepItem', () => { }, well: 'A1', }, - isAirGap: false, source: { postIngreds: { __air__: { @@ -465,7 +459,6 @@ describe('generateSubstepItem', () => { preIngreds: {}, well: 'A2', }, - isAirGap: false, source: { postIngreds: {}, preIngreds: {}, @@ -492,7 +485,6 @@ describe('generateSubstepItem', () => { }, well: 'A2', }, - isAirGap: false, source: { postIngreds: { __air__: { diff --git a/step-generation/src/__tests__/transfer.test.ts b/step-generation/src/__tests__/transfer.test.ts index cd22d6a321b..601f2331425 100644 --- a/step-generation/src/__tests__/transfer.test.ts +++ b/step-generation/src/__tests__/transfer.test.ts @@ -6,6 +6,7 @@ import { WASTE_CHUTE_CUTOUT, } from '@opentrons/shared-data' import { + AIR_GAP_META, ASPIRATE_OFFSET_FROM_BOTTOM_MM, DEFAULT_PIPETTE, delayCommand, @@ -1319,7 +1320,7 @@ describe('advanced options', () => { // dispense the aspirate > air gap { commandType: 'dispense', - + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', @@ -1629,6 +1630,7 @@ describe('advanced options', () => { // dispense aspirate > air gap then liquid { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', @@ -2036,6 +2038,7 @@ describe('advanced options', () => { // dispense the aspirate > air gap { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', @@ -2342,6 +2345,7 @@ describe('advanced options', () => { }, { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { flowRate: 2.2, @@ -2777,6 +2781,7 @@ describe('advanced options', () => { { commandType: 'dispense', key: expect.any(String), + meta: AIR_GAP_META, params: { pipetteId: 'p300SingleId', volume: 31, @@ -3083,6 +3088,7 @@ describe('advanced options', () => { // dispense "aspirate > air gap" then dispense liquid { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', @@ -3515,6 +3521,7 @@ describe('advanced options', () => { // dispense { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', @@ -3879,6 +3886,7 @@ describe('advanced options', () => { // dispense "aspirate > air gap" then dispense liquid { commandType: 'dispense', + meta: AIR_GAP_META, key: expect.any(String), params: { pipetteId: 'p300SingleId', diff --git a/step-generation/src/commandCreators/atomic/aspirate.ts b/step-generation/src/commandCreators/atomic/aspirate.ts index 6d64cf00e7d..c2a596d68ac 100644 --- a/step-generation/src/commandCreators/atomic/aspirate.ts +++ b/step-generation/src/commandCreators/atomic/aspirate.ts @@ -26,7 +26,6 @@ import type { Point } from '../../utils' export interface ExtendedAspirateParams extends AspDispAirgapParams { tipRack: string nozzles: NozzleConfigurationStyle | null - isAirGap?: boolean } /** Aspirate with given args. Requires tip. */ export const aspirate: CommandCreator = ( diff --git a/step-generation/src/commandCreators/atomic/dispense.ts b/step-generation/src/commandCreators/atomic/dispense.ts index 2ca1c737d08..3948158fa6b 100644 --- a/step-generation/src/commandCreators/atomic/dispense.ts +++ b/step-generation/src/commandCreators/atomic/dispense.ts @@ -26,6 +26,7 @@ import type { CommandCreator, CommandCreatorError } from '../../types' export interface DispenseAtomicCommandParams extends DispenseParams { nozzles: NozzleConfigurationStyle | null tipRack: string + isAirGap?: boolean } /** Dispense with given args. Requires tip. */ export const dispense: CommandCreator = ( @@ -42,6 +43,7 @@ export const dispense: CommandCreator = ( wellLocation, nozzles, tipRack, + isAirGap, } = args const actionName = 'dispense' const labwareState = prevRobotState.labware @@ -224,6 +226,7 @@ export const dispense: CommandCreator = ( // pushOut will always be undefined in step-generation for now // since there is no easy way to allow users to for it in PD }, + ...(isAirGap && { meta: { isAirGap } }), }, ] return { diff --git a/step-generation/src/commandCreators/compound/distribute.ts b/step-generation/src/commandCreators/compound/distribute.ts index de87cffd29d..4a5331342cf 100644 --- a/step-generation/src/commandCreators/compound/distribute.ts +++ b/step-generation/src/commandCreators/compound/distribute.ts @@ -257,6 +257,7 @@ export const distribute: CommandCreator = ( }, nozzles, tipRack: args.tipRack, + isAirGap: true, }), ...(dispenseDelay != null ? [ diff --git a/step-generation/src/commandCreators/compound/transfer.ts b/step-generation/src/commandCreators/compound/transfer.ts index adfb9c43887..390d3ff8559 100644 --- a/step-generation/src/commandCreators/compound/transfer.ts +++ b/step-generation/src/commandCreators/compound/transfer.ts @@ -436,6 +436,7 @@ export const transfer: CommandCreator = ( }, tipRack: args.tipRack, nozzles: args.nozzles, + isAirGap: true, }), ...(dispenseDelay != null ? [ diff --git a/step-generation/src/fixtures/commandFixtures.ts b/step-generation/src/fixtures/commandFixtures.ts index aac4662fea0..9e69531ec37 100644 --- a/step-generation/src/fixtures/commandFixtures.ts +++ b/step-generation/src/fixtures/commandFixtures.ts @@ -5,6 +5,7 @@ import { SOURCE_LABWARE, DEFAULT_BLOWOUT_WELL, DEST_LABWARE, + AIR_GAP_META, } from './data' import { ONE_CHANNEL_WASTE_CHUTE_ADDRESSABLE_AREA } from '@opentrons/shared-data' @@ -246,6 +247,7 @@ export const makeDispenseAirGapHelper: MakeDispenseAirGapHelper Date: Fri, 31 Jan 2025 10:36:12 -0500 Subject: [PATCH 04/18] fix(protocol-designer): modify the list button width (#17389) * fix(protocol-designer): modify the list button width --- .../src/molecules/ToggleExpandStepFormField/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx b/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx index 075b9966e16..bccd440570c 100644 --- a/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx +++ b/protocol-designer/src/molecules/ToggleExpandStepFormField/index.tsx @@ -76,6 +76,7 @@ export function ToggleExpandStepFormField( type="noActive" padding={SPACING.spacing12} onClick={onToggleUpdateValue} + width="100%" > From 38e60c3cb54cce741dfc7c0579e0945386e884f4 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:39:18 -0500 Subject: [PATCH 05/18] fix(protocol-designer): fix magnetic module errors (#17395) This PR properly displays error messages for bad engage heights with both the GEN1 and GEN2 magnetic modules in PD. The footprint here is large, because we need to pass the module model to the error creators that determine the module's valid engage height range (specific to model). We also need to pass moduleEntities down through createPresavedStepForm and its patches to set the module model when the form is created or the moduleId is updated. Last, we need to add a migration for the new `moduleModel` field for magnetic module steps. Closes RQA-3911 --- .../StepForm/StepTools/MagnetTools/index.tsx | 8 ++- .../src/step-forms/selectors/index.ts | 29 ++++++++--- .../src/steplist/formLevel/errors.ts | 49 +++++++++++-------- .../src/steplist/formLevel/index.ts | 15 +++--- 4 files changed, 65 insertions(+), 36 deletions(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MagnetTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MagnetTools/index.tsx index 1549f9958a7..8fe0b9e8da8 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MagnetTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MagnetTools/index.tsx @@ -54,14 +54,18 @@ export function MagnetTools(props: StepFormProps): JSX.Element { const mappedErrorsToField = getFormErrorsMappedToField(visibleFormErrors) return ( - + - + = createSelector(getBatchEditFieldChanges, changes => !isEmpty(changes)) -const _formLevelErrors = (hydratedForm: HydratedFormData): StepFormErrors => { - return getFormErrors(hydratedForm.stepType, hydratedForm) +const _formLevelErrors = ( + hydratedForm: HydratedFormData, + moduleEntities: ModuleEntities +): StepFormErrors => { + return getFormErrors(hydratedForm.stepType, hydratedForm, moduleEntities) } const _dynamicFieldFormErrors = ( @@ -638,7 +641,10 @@ export const _hasFormLevelErrors = ( hydratedForm: HydratedFormData, invariantContext: InvariantContext ): boolean => { - if (_formLevelErrors(hydratedForm).length > 0) return true + if ( + _formLevelErrors(hydratedForm, invariantContext.moduleEntities).length > 0 + ) + return true if ( hydratedForm.stepType === 'thermocycler' && @@ -727,13 +733,20 @@ export const getDynamicFieldFormErrorsForUnsavedForm: Selector< export const getFormLevelErrorsForUnsavedForm: Selector< BaseState, StepFormErrors -> = createSelector(getHydratedUnsavedForm, hydratedForm => { - if (!hydratedForm) return [] +> = createSelector( + getHydratedUnsavedForm, + getInvariantContext, + (hydratedForm, invariantContext) => { + if (!hydratedForm) return [] - const errors = _formLevelErrors(hydratedForm) + const errors = _formLevelErrors( + hydratedForm, + invariantContext.moduleEntities + ) - return errors -}) + return errors + } +) export const getCurrentFormCanBeSaved: Selector< BaseState, boolean diff --git a/protocol-designer/src/steplist/formLevel/errors.ts b/protocol-designer/src/steplist/formLevel/errors.ts index eb851637d32..71dd9c859c8 100644 --- a/protocol-designer/src/steplist/formLevel/errors.ts +++ b/protocol-designer/src/steplist/formLevel/errors.ts @@ -21,8 +21,9 @@ import { getTimeFromForm } from '../utils/getTimeFromForm' import type { ReactNode } from 'react' import type { LabwareDefinition2, PipetteV2Specs } from '@opentrons/shared-data' -import type { LabwareEntities, PipetteEntity } from '@opentrons/step-generation' +import type { PipetteEntity } from '@opentrons/step-generation' import type { StepFieldName } from '../../form-types' +import type { ModuleEntities } from '../../step-forms' /******************* ** Error Messages ** ********************/ @@ -113,10 +114,14 @@ const ENGAGE_HEIGHT_REQUIRED: FormError = { const ENGAGE_HEIGHT_MIN_EXCEEDED: FormError = { title: 'Specified distance is below module minimum', dependentFields: ['magnetAction', 'engageHeight'], + showAtForm: false, + showAtField: true, } const ENGAGE_HEIGHT_MAX_EXCEEDED: FormError = { title: 'Specified distance is above module maximum', dependentFields: ['magnetAction', 'engageHeight'], + showAtForm: false, + showAtField: true, } const MODULE_ID_REQUIRED: FormError = { title: @@ -407,7 +412,7 @@ export interface HydratedFormData { export type FormErrorChecker = ( arg: HydratedFormData, - labwareEntities?: LabwareEntities + moduleEntities?: ModuleEntities ) => FormError | null // TODO: test these @@ -672,27 +677,32 @@ export const newLabwareLocationRequired = ( : null } export const engageHeightRangeExceeded = ( - fields: HydratedFormData + fields: HydratedFormData, + moduleEntities?: ModuleEntities ): FormError | null => { - const { magnetAction, engageHeight } = fields - const moduleEntity = fields.meta?.module - const model = moduleEntity?.model - + const { magnetAction, engageHeight, moduleId } = fields + if (moduleEntities == null) { + return null + } + const moduleModel = moduleEntities[moduleId].model + const engageHeightCast = Number(engageHeight) if (magnetAction === 'engage') { - if (model === MAGNETIC_MODULE_V1) { - if (engageHeight < MIN_ENGAGE_HEIGHT_V1) { + if (moduleModel === MAGNETIC_MODULE_V1) { + if (engageHeightCast < MIN_ENGAGE_HEIGHT_V1) { return ENGAGE_HEIGHT_MIN_EXCEEDED - } else if (engageHeight > MAX_ENGAGE_HEIGHT_V1) { + } else if (engageHeightCast > MAX_ENGAGE_HEIGHT_V1) { return ENGAGE_HEIGHT_MAX_EXCEEDED } - } else if (model === MAGNETIC_MODULE_V2) { - if (engageHeight < MIN_ENGAGE_HEIGHT_V2) { + } else if (moduleModel === MAGNETIC_MODULE_V2) { + if (engageHeightCast < MIN_ENGAGE_HEIGHT_V2) { return ENGAGE_HEIGHT_MIN_EXCEEDED - } else if (engageHeight > MAX_ENGAGE_HEIGHT_V2) { + } else if (engageHeightCast > MAX_ENGAGE_HEIGHT_V2) { return ENGAGE_HEIGHT_MAX_EXCEEDED } } else { - console.warn(`unhandled model for engageHeightRangeExceeded: ${model}`) + console.warn( + `unhandled model for engageHeightRangeExceeded: ${moduleModel}` + ) } } @@ -917,14 +927,13 @@ export const fileNameRequired = ( ********************/ type ComposeErrors = ( ...errorCheckers: FormErrorChecker[] -) => (arg: HydratedFormData) => FormError[] +) => (arg: HydratedFormData, moduleEntities?: ModuleEntities) => FormError[] export const composeErrors: ComposeErrors = ( ...errorCheckers: FormErrorChecker[] -) => value => - errorCheckers.reduce((acc, errorChecker) => { - const possibleError = errorChecker(value) - return possibleError ? [...acc, possibleError] : acc - }, []) +) => (formData: HydratedFormData, moduleEntities?: ModuleEntities) => + errorCheckers + .map(checker => checker(formData, moduleEntities)) + .filter((error): error is FormError => error !== null) export const getIsOutOfRange = ( value: any, diff --git a/protocol-designer/src/steplist/formLevel/index.ts b/protocol-designer/src/steplist/formLevel/index.ts index a0b74ec3c16..7242eccb1dd 100644 --- a/protocol-designer/src/steplist/formLevel/index.ts +++ b/protocol-designer/src/steplist/formLevel/index.ts @@ -64,6 +64,7 @@ import { import type { FormWarning, FormWarningType } from './warnings' import type { HydratedFormData, StepType } from '../../form-types' import type { FormError } from './errors' +import type { ModuleEntities } from '@opentrons/step-generation' export { handleFormChange } from './handleFormChange' export { createBlankForm } from './createBlankForm' export { getDefaultsForStepType } from './getDefaultsForStepType' @@ -78,7 +79,10 @@ export { getNextDefaultEngageHeight } from './getNextDefaultEngageHeight' export { stepFormToArgs } from './stepFormToArgs' export type { FormError, FormWarning, FormWarningType } interface FormHelpers { - getErrors?: (arg: HydratedFormData) => FormError[] + getErrors?: ( + arg: HydratedFormData, + moduleEntities: ModuleEntities + ) => FormError[] getWarnings?: (arg: unknown) => FormWarning[] } const stepFormHelperMap: Partial> = { @@ -180,12 +184,11 @@ const stepFormHelperMap: Partial> = { } export const getFormErrors = ( stepType: StepType, - formData: HydratedFormData + formData: HydratedFormData, + moduleEntities: ModuleEntities ): FormError[] => { - const formErrorGetter = - stepFormHelperMap[stepType] && stepFormHelperMap[stepType]?.getErrors - const errors = formErrorGetter != null ? formErrorGetter(formData) : [] - return errors + const formErrorGetter = stepFormHelperMap[stepType]?.getErrors + return formErrorGetter ? formErrorGetter(formData, moduleEntities) : [] } export const getFormWarnings = ( stepType: StepType, From 7eb69e9d0bca644d29a517e97eace86bfbacc79b Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:14:59 -0500 Subject: [PATCH 06/18] fix(protocol-designer): fix StepSummary wrapping (#17401) This PR fixes the wrapping behavior for StepSummary elements. Each component (StyledTrans) of the StepSummary should wrap to the next line dynamically, not have a pre-defined row. Closes RQA-3698 --- .../Designer/ProtocolSteps/StepSummary.tsx | 176 +++++++++--------- 1 file changed, 90 insertions(+), 86 deletions(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx index a7d4349bad6..7077b1812be 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx @@ -3,11 +3,13 @@ import { Trans, useTranslation } from 'react-i18next' import first from 'lodash/first' import flatten from 'lodash/flatten' import last from 'lodash/last' +import styled from 'styled-components' import { ALIGN_CENTER, DIRECTION_COLUMN, Flex, ListItem, + NO_WRAP, SPACING, StyledText, Tag, @@ -41,15 +43,24 @@ function StyledTrans(props: StyledTransProps): JSX.Element { , - semiBoldText: , + text: ( + + ), + semiBoldText: ( + + ), tag: , }} values={values} @@ -57,7 +68,6 @@ function StyledTrans(props: StyledTransProps): JSX.Element { ) } - const getWellsForStepSummary = ( targetWells: string[], labwareWells: string[] @@ -164,63 +174,55 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null { } = currentStep stepSummaryContent = thermocyclerFormType === 'thermocyclerState' ? ( - + {blockIsActive ? ( ) : null} - - {lidIsActive ? ( - - ) : null} + {lidIsActive ? ( - - + ) : null} + + ) : ( - - - - - - - - - - + + + + + + ) break } @@ -383,43 +385,39 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null { getModuleDisplayName(modules[heaterShakerModuleId]?.model) ?? unknownModule stepSummaryContent = ( - - + + + {targetSpeed ? ( - {targetSpeed ? ( - - ) : null} - - - {heaterShakerTimer ? ( - - ) : null} + ) : null} + {heaterShakerTimer ? ( - - + ) : null} + + ) break } @@ -454,3 +452,9 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null { ) : null } + +const StepSummaryContainer = styled(Flex)` + flex-wrap: ${WRAP}; + gap: ${SPACING.spacing20}; + row-gap: ${SPACING.spacing4}; +` From 2525a6353b274162f9edceda0676bdf46dbc8f12 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:58:41 -0500 Subject: [PATCH 07/18] fix(protocol-designer): delete labware if staging area deleted (#17397) If a user has added labware in column 4 provided by a staging area, that labware should be deleted if the hardware is changed such that the staging area is removed. Closes RQA-3907 --- .../Designer/DeckSetup/DeckSetupTools.tsx | 14 +++- .../Designer/DeckSetup/FixtureRender.tsx | 71 ++++++++++++++++--- .../src/pages/Designer/DeckSetup/utils.ts | 14 ++++ protocol-designer/src/utils/index.ts | 23 +++--- 4 files changed, 101 insertions(+), 21 deletions(-) diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx index d997835e831..06fb418d550 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupTools.tsx @@ -301,6 +301,7 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { createdLabwareForSlot.labwareDefURI !== selectedLabwareDefUri || // if nested labware changes but labware doesn't, still delete both (createdLabwareForSlot.labwareDefURI === selectedLabwareDefUri && + selectedNestedLabwareDefUri != null && createdNestedLabwareForSlot?.labwareDefURI !== selectedNestedLabwareDefUri)) ) { @@ -354,6 +355,13 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { dispatch(createDeckFixture(selectedFixture, cutout)) } } + if ( + matchingLabwareFor4thColumn != null && + selectedFixture !== 'stagingArea' && + selectedFixture !== 'wasteChuteAndStagingArea' + ) { + dispatch(deleteContainer({ labwareId: matchingLabwareFor4thColumn.id })) + } if (selectedModuleModel != null) { // create module const moduleType = getModuleType(selectedModuleModel) @@ -411,10 +419,12 @@ export function DeckSetupTools(props: DeckSetupToolsProps): JSX.Element | null { selectedModuleModel != null && selectedLabwareDefUri != null && (createdLabwareForSlot?.labwareDefURI !== selectedLabwareDefUri || - // if nested labware changes but labware doesn't, still create both both + // if nested labware changes but labware doesn't, still create both (createdLabwareForSlot.labwareDefURI === selectedLabwareDefUri && createdNestedLabwareForSlot?.labwareDefURI !== - selectedNestedLabwareDefUri)) + selectedNestedLabwareDefUri && + (createdNestedLabwareForSlot?.labwareDefURI != null || + selectedNestedLabwareDefUri != null))) ) { // create adapter + labware on module dispatch( diff --git a/protocol-designer/src/pages/Designer/DeckSetup/FixtureRender.tsx b/protocol-designer/src/pages/Designer/DeckSetup/FixtureRender.tsx index 3696cd7deaa..116d21b1956 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/FixtureRender.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/FixtureRender.tsx @@ -4,22 +4,29 @@ import { COLORS, FixedTrash, FlexTrash, + Module, SingleSlotFixture, StagingAreaFixture, WasteChuteFixture, WasteChuteStagingAreaFixture, } from '@opentrons/components' -import { OT2_ROBOT_TYPE, getPositionFromSlotId } from '@opentrons/shared-data' +import { + OT2_ROBOT_TYPE, + getModuleDef2, + getPositionFromSlotId, +} from '@opentrons/shared-data' +import { getLabwareSlot } from '@opentrons/step-generation' import { getInitialDeckSetup } from '../../../step-forms/selectors' import { LabwareOnDeck as LabwareOnDeckComponent } from '../../../organisms' import { lightFill, darkFill } from './DeckSetupContainer' -import { getAdjacentLabware } from './utils' +import { getAdjacentSlots } from './utils' import type { TrashCutoutId, StagingAreaLocation, DeckLabelProps, } from '@opentrons/components' import type { + AddressableAreaName, CutoutId, DeckDefinition, RobotType, @@ -38,17 +45,52 @@ interface FixtureRenderProps { export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { const { fixture, cutout, deckDef, robotType, showHighlight, tagInfo } = props const deckSetup = useSelector(getInitialDeckSetup) - const { labware } = deckSetup - const adjacentLabware = getAdjacentLabware(fixture, cutout, labware) + const { labware, modules } = deckSetup + const adjacentSlots = getAdjacentSlots(fixture, cutout) + + // magnetic block in column 3 if staging area is used + const adjacentModule = Object.values(modules).find(({ slot }) => + adjacentSlots?.includes(slot as AddressableAreaName) + ) + // labware in column 3 or 4, possibly on a magnetic block in column 3 + const adjacentLabwares = Object.values(labware).filter( + ({ slot }) => + adjacentSlots?.includes(slot as AddressableAreaName) || + slot === adjacentModule?.id + ) const renderLabwareOnDeck = (): JSX.Element | null => { - if (!adjacentLabware) return null - const slotPosition = getPositionFromSlotId(adjacentLabware.slot, deckDef) return ( - + {adjacentLabwares.map(adjacentLabware => { + const slot = getLabwareSlot(adjacentLabware.id, labware, modules) + const slotPosition = getPositionFromSlotId(slot, deckDef) + return ( + + ) + })} + + ) + } + const renderModuleOnDeck = (): JSX.Element | null => { + if (adjacentModule == null) { + return null + } + const slotPosition = getPositionFromSlotId(adjacentModule.slot, deckDef) + + return ( + ) } @@ -56,13 +98,18 @@ export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { switch (fixture) { case 'stagingArea': { return ( - + 0 ? adjacentLabwares[0]?.id : 0 + }`} + > + {renderModuleOnDeck()} {renderLabwareOnDeck()} ) @@ -105,7 +152,11 @@ export const FixtureRender = (props: FixtureRenderProps): JSX.Element => { } case 'wasteChuteAndStagingArea': { return ( - + 0 ? adjacentLabwares[0]?.id : 0 + }`} + > { + if (fixture === 'stagingArea' || fixture === 'wasteChuteAndStagingArea') { + const stagingAreaAddressableAreaNames = getStagingAreaAddressableAreas( + [cutout], + false + ) + return stagingAreaAddressableAreaNames + } + return null +} + type BreakPoint = 'small' | 'medium' | 'large' export function useDeckSetupWindowBreakPoint(): BreakPoint { diff --git a/protocol-designer/src/utils/index.ts b/protocol-designer/src/utils/index.ts index 8f4c9397066..60c94d4c346 100644 --- a/protocol-designer/src/utils/index.ts +++ b/protocol-designer/src/utils/index.ts @@ -147,19 +147,24 @@ export const getHas96Channel = (pipettes: PipetteEntities): boolean => { } export const getStagingAreaAddressableAreas = ( - cutoutIds: CutoutId[] + cutoutIds: CutoutId[], + filterStandardSlots: boolean = true ): AddressableAreaName[] => { const deckDef = getDeckDefFromRobotType(FLEX_ROBOT_TYPE) const cutoutFixtures = deckDef.cutoutFixtures - return cutoutIds - .flatMap(cutoutId => { - const addressableAreasOnCutout = cutoutFixtures.find( - cutoutFixture => cutoutFixture.id === STAGING_AREA_RIGHT_SLOT_FIXTURE - )?.providesAddressableAreas[cutoutId] - return addressableAreasOnCutout ?? [] - }) - .filter(aa => !isAddressableAreaStandardSlot(aa, deckDef)) + const addressableAreasRaw = cutoutIds.flatMap(cutoutId => { + const addressableAreasOnCutout = cutoutFixtures.find( + cutoutFixture => cutoutFixture.id === STAGING_AREA_RIGHT_SLOT_FIXTURE + )?.providesAddressableAreas[cutoutId] + return addressableAreasOnCutout ?? [] + }) + if (filterStandardSlots) { + return addressableAreasRaw.filter( + aa => !isAddressableAreaStandardSlot(aa, deckDef) + ) + } + return addressableAreasRaw } export const getCutoutIdByAddressableArea = ( From dc48e1007126f782a5de9313005fc4fe99a1270d Mon Sep 17 00:00:00 2001 From: koji Date: Mon, 3 Feb 2025 14:43:53 -0500 Subject: [PATCH 08/18] fix(protocol-designer): fix staging area logic (#17403) * fix(protocol-designer): fix staging area logic --- .../__tests__/utils.test.ts | 71 ++++++++++----- .../pages/CreateNewProtocolWizard/utils.tsx | 89 ++++++++++++++++--- 2 files changed, 126 insertions(+), 34 deletions(-) diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/utils.test.ts b/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/utils.test.ts index a167217bf25..c255fc56ad5 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/utils.test.ts +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/utils.test.ts @@ -237,8 +237,8 @@ describe('getNumSlotsAvailable', () => { mockAdditionalEquipment, 'stagingArea' ) - // Note: the return value is 2 because trashBin can be placed slot1 - expect(result).toBe(2) + + expect(result).toBe(1) }) it('should return 1 when there are 8 modules with 2 magnetic blocks and one trash for staging area', () => { @@ -285,14 +285,14 @@ describe('getNumSlotsAvailable', () => { mockAdditionalEquipment, 'stagingArea' ) - expect(result).toBe(2) + expect(result).toBe(1) }) - it('should return 4 when there are 12 magnetic blocks for staging area', () => { + it('should return 0 when there are 11 magnetic blocks for staging area', () => { const mockModules = { 0: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'D2', }, 1: { model: MAGNETIC_BLOCK_V1, @@ -302,52 +302,47 @@ describe('getNumSlotsAvailable', () => { 2: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'B2', }, 3: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'A2', }, 4: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'D3', }, 5: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'C3', }, 6: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'D2', + slot: 'B3', }, 7: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'D1', }, 8: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'C1', }, 9: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'B1', }, 10: { model: MAGNETIC_BLOCK_V1, type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', - }, - 11: { - model: MAGNETIC_BLOCK_V1, - type: MAGNETIC_BLOCK_TYPE, - slot: 'C2', + slot: 'A1', }, } as any const mockAdditionalEquipment: AdditionalEquipment[] = [] @@ -356,9 +351,39 @@ describe('getNumSlotsAvailable', () => { mockAdditionalEquipment, 'stagingArea' ) - expect(result).toBe(4) + // Note: the return value is 0 because trashBin A3 + expect(result).toBe(0) + }) + + it('should return 3 when slots in column 1 are occupied', () => { + const mockModules = { + 0: { + model: TEMPERATURE_MODULE_V2, + type: TEMPERATURE_MODULE_TYPE, + slot: 'D1', + }, + 1: { + model: HEATERSHAKER_MODULE_V1, + type: HEATERSHAKER_MODULE_TYPE, + slot: 'C1', + }, + 2: { + model: THERMOCYCLER_MODULE_V2, + type: THERMOCYCLER_MODULE_TYPE, + slot: 'B1', + }, + } as any + const mockAdditionalEquipment: AdditionalEquipment[] = ['trashBin'] + const result = getNumSlotsAvailable( + mockModules, + mockAdditionalEquipment, + 'stagingArea' + ) + + expect(result).toBe(3) }) - it('should return 12 when there are 4 staging area for magnetic block', () => { + + it('should return 11 when there are 4 staging area for magnetic block', () => { const mockAdditionalEquipment: AdditionalEquipment[] = [ 'stagingArea', 'stagingArea', @@ -370,7 +395,7 @@ describe('getNumSlotsAvailable', () => { mockAdditionalEquipment, MAGNETIC_BLOCK_V1 ) - expect(result).toBe(12) + expect(result).toBe(11) }) it('should return 8 when there are 4 modules, 4 staging area for magnetic block since magnetic blocks can now go on staging areas', () => { const mockModules = { @@ -401,7 +426,7 @@ describe('getNumSlotsAvailable', () => { mockAdditionalEquipment, MAGNETIC_BLOCK_V1 ) - expect(result).toBe(8) + expect(result).toBe(7) }) }) diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/utils.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/utils.tsx index 69abb7e6ae7..1ae5f54ac2d 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/utils.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/utils.tsx @@ -1,13 +1,16 @@ import { + ABSORBANCE_READER_TYPE, ABSORBANCE_READER_V1, getLabwareDefURI, getLabwareDisplayName, getPipetteSpecsV2, + HEATERSHAKER_MODULE_TYPE, HEATERSHAKER_MODULE_V1, MAGNETIC_BLOCK_TYPE, MAGNETIC_BLOCK_V1, MAGNETIC_MODULE_V1, MAGNETIC_MODULE_V2, + TEMPERATURE_MODULE_TYPE, TEMPERATURE_MODULE_V1, TEMPERATURE_MODULE_V2, THERMOCYCLER_MODULE_TYPE, @@ -32,8 +35,9 @@ import type { AdditionalEquipment, WizardFormState } from './types' const NUM_SLOTS_OUTER = 8 const NUM_SLOTS_MIDDLE = 4 -const NUM_SLOTS_COLUMN3 = 4 -const NUM_SLOTS_MAGNETIC_BLOCK = 12 +const NUM_SLOTS_COLUMN1 = 4 +// Note (1/31/25): change the max from 12 to 11 because of a fixture(trash bin/waste chute) +const NUM_SLOTS_MAGNETIC_BLOCK = 11 export const getNumOptions = (length: number): DropdownOption[] => { return Array.from({ length }, (_, i) => ({ @@ -42,6 +46,43 @@ export const getNumOptions = (length: number): DropdownOption[] => { })) } +// Note (1/31/25): at this moment, users allow to set one about thermocycler and need to count 2 +interface ModuleCounts { + magneticBlockCount: number + heaterShakerCount: number + temperatureCount: number + plateReaderCount: number +} + +const countModules = (modules: WizardFormState['modules']): ModuleCounts => { + return Object.values(modules || {}).reduce( + (acc, module) => { + switch (module.type) { + case MAGNETIC_BLOCK_TYPE: + acc.magneticBlockCount += 1 + break + case HEATERSHAKER_MODULE_TYPE: + acc.heaterShakerCount += 1 + break + case TEMPERATURE_MODULE_TYPE: + acc.temperatureCount += 1 + break + case ABSORBANCE_READER_TYPE: + acc.plateReaderCount += 1 + break + default: + break + } + return acc + }, + { + magneticBlockCount: 0, + heaterShakerCount: 0, + temperatureCount: 0, + plateReaderCount: 0, + } + ) +} export const getNumSlotsAvailable = ( modules: WizardFormState['modules'], additionalEquipment: WizardFormState['additionalEquipment'], @@ -115,16 +156,42 @@ export const getNumSlotsAvailable = ( } case 'stagingArea': { - const modulesWithColumn3 = - modules !== null - ? Object.values(modules).filter(module => module.slot?.includes('3')) - .length - : 0 - const fixtureSlotsWithColumn3 = - additionalEquipment !== null - ? additionalEquipment.filter(slot => slot.includes('3')).length + const { + magneticBlockCount, + heaterShakerCount, + temperatureCount, + plateReaderCount, + } = countModules(modules) + + // Note (kk: 1/31/25) magnetic modules are placed in the middle slots first + // then it will be placed in the column 1 slots and column 3 slots + // the way to distribute magnetic modules like D1 -> D3 -> C1 -> C3 + const adjustMagneticBlockCount = + magneticBlockCount - NUM_SLOTS_MIDDLE > 0 + ? magneticBlockCount - NUM_SLOTS_MIDDLE : 0 - return NUM_SLOTS_COLUMN3 - modulesWithColumn3 - fixtureSlotsWithColumn3 + + const thermocyclerModuleCount = hasTC ? 2 : 0 + + const totalModules = + adjustMagneticBlockCount + + heaterShakerCount + + temperatureCount + + thermocyclerModuleCount + + // if the following is more than 0, pd will need to keep one slot in column 3 for trash bin/waste chute + const requiredSlotInColumn3 = + totalModules - NUM_SLOTS_COLUMN1 >= 0 ? 1 : 0 + + // there is two cases pd considers + // 1. stating area can slots in column 3 because trash bin can be a slot in column 1 + // 2. not case 1 which is very limited + return totalModules <= NUM_SLOTS_COLUMN1 + ? NUM_SLOTS_COLUMN1 - plateReaderCount - requiredSlotInColumn3 + : NUM_SLOTS_OUTER - + totalModules - + plateReaderCount - + requiredSlotInColumn3 } case 'wasteChute': { From e37b61f017b55412649d2d275e1e38ec7c19de6e Mon Sep 17 00:00:00 2001 From: koji Date: Tue, 4 Feb 2025 10:32:48 -0500 Subject: [PATCH 09/18] fix(protocol-designer, components) fix deck view size issue (#17394) * fix(protocol-designer, components) fix deck view size issue --- .../src/atoms/buttons/EmptySelectorButton.tsx | 5 +- protocol-designer/src/ProtocolEditor.tsx | 2 +- protocol-designer/src/ProtocolRoutes.tsx | 2 +- .../Designer/DeckSetup/DeckSetupContainer.tsx | 295 ++++++++++-------- .../HighlightOffdeckSlot.tsx | 0 .../{Offdeck => OffDeck}/OffDeckDetails.tsx | 79 +++-- .../__tests__/OffDeck.test.tsx} | 2 +- .../__tests__/OffDeckDetails.test.tsx | 0 .../Offdeck.tsx => OffDeck/index.tsx} | 0 .../src/pages/Designer/Offdeck/index.ts | 1 - .../ProtocolSteps/DraggableSidebar.tsx | 2 +- .../Designer/ProtocolSteps/StepSummary.tsx | 7 +- .../__tests__/ProtocolSteps.test.tsx | 4 +- .../pages/Designer/ProtocolSteps/index.tsx | 37 ++- .../Designer/__tests__/Designer.test.tsx | 1 + .../src/pages/Designer/index.tsx | 34 +- 16 files changed, 268 insertions(+), 203 deletions(-) rename protocol-designer/src/pages/Designer/{Offdeck => OffDeck}/HighlightOffdeckSlot.tsx (100%) rename protocol-designer/src/pages/Designer/{Offdeck => OffDeck}/OffDeckDetails.tsx (84%) rename protocol-designer/src/pages/Designer/{Offdeck/__tests__/Offdeck.test.tsx => OffDeck/__tests__/OffDeck.test.tsx} (97%) rename protocol-designer/src/pages/Designer/{Offdeck => OffDeck}/__tests__/OffDeckDetails.test.tsx (100%) rename protocol-designer/src/pages/Designer/{Offdeck/Offdeck.tsx => OffDeck/index.tsx} (100%) delete mode 100644 protocol-designer/src/pages/Designer/Offdeck/index.ts diff --git a/components/src/atoms/buttons/EmptySelectorButton.tsx b/components/src/atoms/buttons/EmptySelectorButton.tsx index da34a8ba710..119ff041ba9 100644 --- a/components/src/atoms/buttons/EmptySelectorButton.tsx +++ b/components/src/atoms/buttons/EmptySelectorButton.tsx @@ -4,7 +4,6 @@ import { ALIGN_CENTER, CURSOR_DEFAULT, CURSOR_POINTER, - FLEX_MAX_CONTENT, Icon, JUSTIFY_CENTER, JUSTIFY_START, @@ -62,8 +61,8 @@ interface ButtonProps { const StyledButton = styled.button` border: none; - width: ${FLEX_MAX_CONTENT}; - height: ${FLEX_MAX_CONTENT}; + width: 100%; + height: 100%; cursor: ${CURSOR_POINTER}; background-color: ${COLORS.blue30}; border-radius: ${BORDERS.borderRadius8}; diff --git a/protocol-designer/src/ProtocolEditor.tsx b/protocol-designer/src/ProtocolEditor.tsx index ec0a130abd5..770e3ee0a42 100644 --- a/protocol-designer/src/ProtocolEditor.tsx +++ b/protocol-designer/src/ProtocolEditor.tsx @@ -38,7 +38,7 @@ export function ProtocolEditor(): JSX.Element { id="protocol-editor" > - + diff --git a/protocol-designer/src/ProtocolRoutes.tsx b/protocol-designer/src/ProtocolRoutes.tsx index 854eacfa993..63c31842bbe 100644 --- a/protocol-designer/src/ProtocolRoutes.tsx +++ b/protocol-designer/src/ProtocolRoutes.tsx @@ -73,7 +73,7 @@ export function ProtocolRoutes(): JSX.Element { > - + diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx index 53874bb8dc0..c9c351aebb1 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx @@ -6,15 +6,15 @@ import { BORDERS, Box, COLORS, - DIRECTION_COLUMN, DeckFromLayers, + DIRECTION_COLUMN, Flex, FlexTrash, JUSTIFY_CENTER, RobotCoordinateSpaceWithRef, - SPACING, SingleSlotFixture, SlotLabels, + SPACING, StagingAreaFixture, WasteChuteFixture, WasteChuteStagingAreaFixture, @@ -59,6 +59,9 @@ import type { Fixture } from './constants' const WASTE_CHUTE_SPACE = 30 const DETAILS_HOVER_SPACE = 60 +// Note (02/02/25:kk) the size is different from the design but the product team requested keep the current size +const STARTING_DECK_VIEW_MIN_WIDTH = '75%' + const OT2_STANDARD_DECK_VIEW_LAYER_BLOCK_LIST: string[] = [ 'calibrationMarkings', 'fixedBase', @@ -213,15 +216,24 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { aa => isAddressableAreaStandardSlot(aa.id, deckDef) ) + let containerPadding = '0' + if (!isZoomed) { + if (tab === 'startingDeck') { + containerPadding = SPACING.spacing40 + } else { + containerPadding = SPACING.spacing60 + } + } + return ( - + <> - {zoomIn.slot == null ? ( + {zoomIn.slot == null && tab === 'startingDeck' ? ( {hoverSlot != null && breakPointSize !== 'small' && @@ -239,144 +251,153 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { ) : null} ) : null} - - {() => ( - <> - {robotType === OT2_ROBOT_TYPE ? ( - - ) : ( - <> - {filteredAddressableAreas.map(addressableArea => { - const cutoutId = getCutoutIdForAddressableArea( - addressableArea.id, - deckDef.cutoutFixtures - ) - return cutoutId != null ? ( - - ) : null - })} - {stagingAreaFixtures.map(fixture => { - if ( - zoomIn.cutout == null || - zoomIn.cutout !== fixture.location - ) { - return ( - - ) - } - })} - {trash != null - ? trashBinFixtures.map(({ cutoutId }) => - cutoutId != null && - (zoomIn.cutout == null || - zoomIn.cutout !== cutoutId) ? ( - - - - - ) : null + + {() => ( + <> + {robotType === OT2_ROBOT_TYPE ? ( + + ) : ( + <> + {filteredAddressableAreas.map(addressableArea => { + const cutoutId = getCutoutIdForAddressableArea( + addressableArea.id, + deckDef.cutoutFixtures ) - : null} - {wasteChuteFixtures.map(fixture => { - if ( - zoomIn.cutout == null || - zoomIn.cutout !== fixture.location - ) { - return ( - - ) - } - })} - {wasteChuteStagingAreaFixtures.map(fixture => { - if ( - zoomIn.cutout == null || - zoomIn.cutout !== fixture.location - ) { - return ( - - ) - } - })} - - )} - areas.location as CutoutId + ) : null + })} + {stagingAreaFixtures.map(fixture => { + if ( + zoomIn.cutout == null || + zoomIn.cutout !== fixture.location + ) { + return ( + + ) + } + })} + {trash != null + ? trashBinFixtures.map(({ cutoutId }) => + cutoutId != null && + (zoomIn.cutout == null || + zoomIn.cutout !== cutoutId) ? ( + + + + + ) : null + ) + : null} + {wasteChuteFixtures.map(fixture => { + if ( + zoomIn.cutout == null || + zoomIn.cutout !== fixture.location + ) { + return ( + + ) + } + })} + {wasteChuteStagingAreaFixtures.map(fixture => { + if ( + zoomIn.cutout == null || + zoomIn.cutout !== fixture.location + ) { + return ( + + ) + } + })} + )} - {...{ - deckDef, - showGen1MultichannelCollisionWarnings, - }} - /> - 0} - /> - - )} - - {zoomIn.slot == null ? ( + areas.location as CutoutId + )} + {...{ + deckDef, + showGen1MultichannelCollisionWarnings, + }} + /> + 0} + /> + + )} + + + {zoomIn.slot == null && tab === 'startingDeck' ? ( {hoverSlot != null && breakPointSize !== 'small' && @@ -404,6 +425,6 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { setHoveredLabware={setHoveredLabware} /> ) : null} - + ) } diff --git a/protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx b/protocol-designer/src/pages/Designer/OffDeck/HighlightOffdeckSlot.tsx similarity index 100% rename from protocol-designer/src/pages/Designer/Offdeck/HighlightOffdeckSlot.tsx rename to protocol-designer/src/pages/Designer/OffDeck/HighlightOffdeckSlot.tsx diff --git a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx b/protocol-designer/src/pages/Designer/OffDeck/OffDeckDetails.tsx similarity index 84% rename from protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx rename to protocol-designer/src/pages/Designer/OffDeck/OffDeckDetails.tsx index 5f219e8ecd1..b062915271c 100644 --- a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx +++ b/protocol-designer/src/pages/Designer/OffDeck/OffDeckDetails.tsx @@ -1,9 +1,12 @@ import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' +import styled from 'styled-components' import { ALIGN_CENTER, + ALIGN_START, BORDERS, + Box, COLORS, DIRECTION_COLUMN, EmptySelectorButton, @@ -14,7 +17,6 @@ import { RobotWorkSpace, SPACING, StyledText, - WRAP, } from '@opentrons/components' import * as wellContentsSelectors from '../../../top-selectors/well-contents' import { selectors } from '../../../labware-ingred/selectors' @@ -32,7 +34,9 @@ import { HighlightOffdeckSlot } from './HighlightOffdeckSlot' import type { CoordinateTuple, DeckSlotId } from '@opentrons/shared-data' import type { DeckSetupTabType } from '../types' -const OFFDECK_MAP_WIDTH = '41.625rem' +const OFF_DECK_MAP_WIDTH = '41.625rem' +const OFF_DECK_MAP_HEIGHT = '45.5rem' +const OFF_DECK_MAP_HEIGHT_FOR_STEP = '31.4rem' const ZERO_SLOT_POSITION: CoordinateTuple = [0, 0, 0] interface OffDeckDetailsProps extends DeckSetupTabType { addLabware: () => void @@ -53,27 +57,29 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { const allWellContentsForActiveItem = useSelector( wellContentsSelectors.getAllWellContentsForActiveItem ) - const containerWidth = tab === 'startingDeck' ? '100vw' : '75vh' + const containerWidth = tab === 'startingDeck' ? '100vw' : '75vw' + const paddingLeftWithHover = hoverSlot == null - ? `calc((${containerWidth} - (${SPACING.spacing24} * 2) - ${OFFDECK_MAP_WIDTH}) / 2)` + ? `calc((${containerWidth} - (${SPACING.spacing24} * 2) - ${OFF_DECK_MAP_WIDTH}) / 2)` : SPACING.spacing24 const paddingLeft = tab === 'startingDeck' ? paddingLeftWithHover : undefined const padding = tab === 'protocolSteps' ? SPACING.spacing24 - : `${SPACING.spacing24} ${paddingLeft}` - const stepDetailsContainerWidth = `calc(((${containerWidth} - ${OFFDECK_MAP_WIDTH}) / 2) - (${SPACING.spacing24} * 3))` + : `${SPACING.spacing40} ${paddingLeft}` + const stepDetailsContainerWidth = `calc(((${containerWidth} - ${OFF_DECK_MAP_WIDTH}) / 2) - (${SPACING.spacing24} * 3))` return ( {hoverSlot != null ? ( @@ -85,27 +91,41 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { ) : null} {i18n.format(t('off_deck_labware'), 'upperCase')} - - + + {tab === 'startingDeck' ? ( + + + + ) : null} {offDeckLabware.map(lw => { const wellContents = allWellContentsForActiveItem ? allWellContentsForActiveItem[lw.id] @@ -123,13 +143,11 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { const highlighted = hoveredDropdownItem.id === lw.id return ( ) })} - - - {tab === 'startingDeck' ? ( - - - - ) : null} - + ) } + +const LabwareWrapper = styled(Box)` + display: grid; + grid-template-columns: repeat(auto-fill, minmax(9.5625rem, 1fr)); + row-gap: ${SPACING.spacing40}; + column-gap: ${SPACING.spacing32}; + justify-content: ${JUSTIFY_CENTER}; /* Center the grid within the container */ + align-items: ${ALIGN_START}; + width: 100%; + // Note(kk: 1/30/2025) this padding is to add space to the right edge and the left edge of the grid + // this is not a perfect solution, but it works for now + padding: 0 ${SPACING.spacing24}; +` diff --git a/protocol-designer/src/pages/Designer/Offdeck/__tests__/Offdeck.test.tsx b/protocol-designer/src/pages/Designer/OffDeck/__tests__/OffDeck.test.tsx similarity index 97% rename from protocol-designer/src/pages/Designer/Offdeck/__tests__/Offdeck.test.tsx rename to protocol-designer/src/pages/Designer/OffDeck/__tests__/OffDeck.test.tsx index 54edbf8e9ac..11bea47d9d0 100644 --- a/protocol-designer/src/pages/Designer/Offdeck/__tests__/Offdeck.test.tsx +++ b/protocol-designer/src/pages/Designer/OffDeck/__tests__/OffDeck.test.tsx @@ -5,7 +5,7 @@ import { selectors } from '../../../../labware-ingred/selectors' import { getCustomLabwareDefsByURI } from '../../../../labware-defs/selectors' import { renderWithProviders } from '../../../../__testing-utils__' import { OffDeckDetails } from '../OffDeckDetails' -import { OffDeck } from '../Offdeck' +import { OffDeck } from '..' import type * as Components from '@opentrons/components' vi.mock('../OffDeckDetails') diff --git a/protocol-designer/src/pages/Designer/Offdeck/__tests__/OffDeckDetails.test.tsx b/protocol-designer/src/pages/Designer/OffDeck/__tests__/OffDeckDetails.test.tsx similarity index 100% rename from protocol-designer/src/pages/Designer/Offdeck/__tests__/OffDeckDetails.test.tsx rename to protocol-designer/src/pages/Designer/OffDeck/__tests__/OffDeckDetails.test.tsx diff --git a/protocol-designer/src/pages/Designer/Offdeck/Offdeck.tsx b/protocol-designer/src/pages/Designer/OffDeck/index.tsx similarity index 100% rename from protocol-designer/src/pages/Designer/Offdeck/Offdeck.tsx rename to protocol-designer/src/pages/Designer/OffDeck/index.tsx diff --git a/protocol-designer/src/pages/Designer/Offdeck/index.ts b/protocol-designer/src/pages/Designer/Offdeck/index.ts deleted file mode 100644 index 0ca8caf1f01..00000000000 --- a/protocol-designer/src/pages/Designer/Offdeck/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Offdeck' diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/DraggableSidebar.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/DraggableSidebar.tsx index 210abdec6ba..f1f66879c41 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/DraggableSidebar.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/DraggableSidebar.tsx @@ -10,7 +10,7 @@ import { } from '@opentrons/components' import { TimelineToolbox } from './Timeline/TimelineToolbox' -const INITIAL_SIDEBAR_WIDTH = 276 +const INITIAL_SIDEBAR_WIDTH = 235 const MIN_SIDEBAR_WIDTH = 80 const MAX_SIDEBAR_WIDTH = 350 diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx index 7077b1812be..1daf86148ee 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx @@ -40,11 +40,7 @@ function StyledTrans(props: StyledTransProps): JSX.Element { const { i18nKey, tagText, values } = props const { t } = useTranslation(['protocol_steps', 'application']) return ( - + {stepSummaryContent != null ? ( diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx index 31c1c93eafc..d333baf288d 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx @@ -18,14 +18,14 @@ import { } from '../../../../file-data/selectors' import { getEnableHotKeysDisplay } from '../../../../feature-flags/selectors' import { DeckSetupContainer } from '../../DeckSetup' -import { OffDeck } from '../../Offdeck' +import { OffDeck } from '../../OffDeck' import { SubStepsToolbox } from '../Timeline' import { DraggableSidebar } from '../DraggableSidebar' import { ProtocolSteps } from '..' import type { SavedStepFormState } from '../../../../step-forms' -vi.mock('../../Offdeck') +vi.mock('../../OffDeck') vi.mock('../../../../step-forms/selectors') vi.mock('../../../../ui/steps/selectors') vi.mock('../../../../ui/labware/selectors') diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index e426affd60d..8ef8f52d8e8 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -31,7 +31,7 @@ import { getHoveredTerminalItemId, } from '../../../ui/steps/selectors' import { DeckSetupContainer } from '../DeckSetup' -import { OffDeck } from '../Offdeck' +import { OffDeck } from '../OffDeck' import { SubStepsToolbox } from './Timeline' import { StepForm } from './StepForm' import { StepSummary } from './StepSummary' @@ -43,7 +43,7 @@ import { import { TimelineAlerts } from '../../../organisms' import { DraggableSidebar } from './DraggableSidebar' -const CONTENT_MAX_WIDTH = '44.6704375rem' +const CONTENT_MAX_WIDTH = '46.9375rem' export function ProtocolSteps(): JSX.Element { const { i18n, t } = useTranslation('starting_deck_state') @@ -52,14 +52,15 @@ export function ProtocolSteps(): JSX.Element { const hoveredTerminalItem = useSelector(getHoveredTerminalItemId) const isMultiSelectMode = useSelector(getIsMultiSelectMode) const selectedSubstep = useSelector(getSelectedSubstep) - const enableHoyKeyDisplay = useSelector(getEnableHotKeysDisplay) + const enableHotKeyDisplay = useSelector(getEnableHotKeysDisplay) const tab = useSelector(getDesignerTab) const leftString = t('onDeck') const rightString = t('offDeck') const [deckView, setDeckView] = useState< typeof leftString | typeof rightString >(leftString) - const [targetWidth, setTargetWidth] = useState(350) + // Note (02/03/25:kk) use DrraggableSidebar's initial width + const [targetWidth, setTargetWidth] = useState(235) const currentHoveredStepId = useSelector(getHoveredStepId) const currentSelectedStepId = useSelector(getSelectedStepId) @@ -82,12 +83,11 @@ export function ProtocolSteps(): JSX.Element { - + {showTimelineAlerts ? ( )} - {formData == null ? ( + {/* avoid shifting the deck view container */} + - ) : null} + - {enableHoyKeyDisplay ? ( + {enableHotKeyDisplay ? ( ) : null} - + + + + {isMultiSelectMode ? : null} ) diff --git a/protocol-designer/src/pages/Designer/__tests__/Designer.test.tsx b/protocol-designer/src/pages/Designer/__tests__/Designer.test.tsx index d7a05a8efe0..9480ebc2d45 100644 --- a/protocol-designer/src/pages/Designer/__tests__/Designer.test.tsx +++ b/protocol-designer/src/pages/Designer/__tests__/Designer.test.tsx @@ -16,6 +16,7 @@ import type { NavigateFunction } from 'react-router-dom' const mockNavigate = vi.fn() +vi.mock('../OffDeck') vi.mock('../ProtocolSteps') vi.mock('../../../labware-ingred/actions') vi.mock('../../../labware-ingred/selectors') diff --git a/protocol-designer/src/pages/Designer/index.tsx b/protocol-designer/src/pages/Designer/index.tsx index 5e560fcf6e4..792d3f25f4f 100644 --- a/protocol-designer/src/pages/Designer/index.tsx +++ b/protocol-designer/src/pages/Designer/index.tsx @@ -3,12 +3,14 @@ import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' import { - ALIGN_END, + ALIGN_CENTER, + ALIGN_STRETCH, COLORS, DIRECTION_COLUMN, - FLEX_MAX_CONTENT, Flex, INFO_TOAST, + JUSTIFY_CENTER, + JUSTIFY_FLEX_END, SPACING, ToggleGroup, useOnClickOutside, @@ -25,7 +27,7 @@ import { selectDesignerTab } from '../../file-data/actions' import { getDesignerTab, getFileMetadata } from '../../file-data/selectors' import { DeckSetupContainer } from './DeckSetup' import { selectors } from '../../labware-ingred/selectors' -import { OffDeck } from './Offdeck' +import { OffDeck } from './OffDeck' import { LiquidsOverflowMenu } from './LiquidsOverflowMenu' import { ProtocolSteps } from './ProtocolSteps' @@ -126,7 +128,14 @@ export function Designer(): JSX.Element { const deckViewItems = deckView === leftString ? ( - + + + ) : ( ) @@ -159,7 +168,7 @@ export function Designer(): JSX.Element { }} /> ) : null} - + {zoomIn.slot == null ? ( - + Date: Tue, 4 Feb 2025 14:40:49 -0500 Subject: [PATCH 10/18] fix(protocol-designer): fix empty selector button size issue (#17418) * fix(protocol-designer): fix empty selector button size issue --- .../EditInstrumentsModal/PipetteOverview.tsx | 39 +++++++------- .../SelectFixtures.tsx | 36 ++++++------- .../CreateNewProtocolWizard/SelectModules.tsx | 3 +- .../SelectPipettes.tsx | 23 +++++---- .../AbsorbanceReaderTools/Initialization.tsx | 15 +++--- .../ThermocyclerProfileModal.tsx | 51 +++++++++++-------- 6 files changed, 94 insertions(+), 73 deletions(-) diff --git a/protocol-designer/src/organisms/EditInstrumentsModal/PipetteOverview.tsx b/protocol-designer/src/organisms/EditInstrumentsModal/PipetteOverview.tsx index b058901c07f..1790d2c089a 100644 --- a/protocol-designer/src/organisms/EditInstrumentsModal/PipetteOverview.tsx +++ b/protocol-designer/src/organisms/EditInstrumentsModal/PipetteOverview.tsx @@ -9,6 +9,7 @@ import { DIRECTION_COLUMN, DIRECTION_ROW, EmptySelectorButton, + FLEX_MAX_CONTENT, Flex, Icon, JUSTIFY_SPACE_BETWEEN, @@ -179,15 +180,17 @@ export function PipetteOverview({ ) : null} {has96Channel || (leftPipette != null && rightPipette != null) ? null : ( - { - setPage('add') - setMount(targetPipetteMount) - }} - text={t('add_pipette')} - textAlignment="left" - iconName="plus" - /> + + { + setPage('add') + setMount(targetPipetteMount) + }} + text={t('add_pipette')} + textAlignment="left" + iconName="plus" + /> + )} @@ -238,14 +241,16 @@ export function PipetteOverview({ ) : ( - { - dispatch(toggleIsGripperRequired()) - }} - text={t('protocol_overview:add_gripper')} - textAlignment="left" - iconName="plus" - /> + + { + dispatch(toggleIsGripperRequired()) + }} + text={t('protocol_overview:add_gripper')} + textAlignment="left" + iconName="plus" + /> + )} diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx index 19eb12cb2db..0cb0039dbe5 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx @@ -8,6 +8,7 @@ import { DIRECTION_COLUMN, EmptySelectorButton, Flex, + FLEX_MAX_CONTENT, ListItem, SPACING, StyledText, @@ -99,23 +100,24 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null { ) return ( - { - if (numSlotsAvailable === 0) { - makeSnackbar(t('slots_limit_reached') as string) - } else { - setValue('additionalEquipment', [ - ...additionalEquipment, - equipment, - ]) - } - }} - /> + + { + if (numSlotsAvailable === 0) { + makeSnackbar(t('slots_limit_reached') as string) + } else { + setValue('additionalEquipment', [ + ...additionalEquipment, + equipment, + ]) + } + }} + /> + ) })} diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx index 717a6b2b762..fc09ad03517 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx @@ -5,6 +5,7 @@ import { COLORS, DIRECTION_COLUMN, EmptySelectorButton, + FLEX_MAX_CONTENT, Flex, ListItem, SPACING, @@ -320,7 +321,7 @@ function AddModuleEmptySelectorButton( return ( <> - + { - setPage('add') - setMount(targetPipetteMount) - resetFields() - }} - text={t('add_pipette')} - textAlignment="left" - iconName="plus" - /> + + { + setPage('add') + setMount(targetPipetteMount) + resetFields() + }} + text={t('add_pipette')} + textAlignment="left" + iconName="plus" + /> + )} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx index 1b388e8f4ea..1b6c5252917 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx @@ -10,6 +10,7 @@ import { Divider, DropdownMenu, EmptySelectorButton, + FLEX_MAX_CONTENT, Flex, Icon, InputField, @@ -237,12 +238,14 @@ function IntializationEditor(props: InitializationEditorProps): JSX.Element { {wavelengthItems} {mode === 'multi' && wavelengths.length < MAX_WAVELENGTHS ? ( - + + + ) : null} {mode === 'single' ? ( diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/ThermocyclerProfileModal.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/ThermocyclerProfileModal.tsx index b1f87f6f997..3b9a6357dd8 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/ThermocyclerProfileModal.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/ThermocyclerTools/ThermocyclerProfileModal.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { DIRECTION_COLUMN, EmptySelectorButton, + FLEX_MAX_CONTENT, Flex, InfoScreen, JUSTIFY_FLEX_END, @@ -98,28 +99,34 @@ export function ThermocyclerProfileModal( maxHeight="31.875rem" > - { - if (canAddStepOrProfile) { - setShowCreateNewCycle(true) - } - }} - textAlignment="left" - iconName="plus" - disabled={!canAddStepOrProfile} - /> - { - if (canAddStepOrProfile) { - setShowCreateNewStep(true) - } - }} - textAlignment="left" - iconName="plus" - disabled={!canAddStepOrProfile} - /> + + { + if (canAddStepOrProfile) { + setShowCreateNewCycle(true) + } + }} + textAlignment="left" + iconName="plus" + disabled={!canAddStepOrProfile} + /> + + + { + if (canAddStepOrProfile) { + setShowCreateNewStep(true) + } + }} + textAlignment="left" + iconName="plus" + disabled={!canAddStepOrProfile} + /> + {steps.length > 0 || showCreateNewStep || showCreateNewCycle ? ( Date: Tue, 4 Feb 2025 16:00:11 -0500 Subject: [PATCH 11/18] fix(components): Fix large button outline issue (#17415) * fix(components): Fix large button outline issue --- components/src/atoms/buttons/LargeButton.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/src/atoms/buttons/LargeButton.tsx b/components/src/atoms/buttons/LargeButton.tsx index cea665221fe..cccf1c0fd09 100644 --- a/components/src/atoms/buttons/LargeButton.tsx +++ b/components/src/atoms/buttons/LargeButton.tsx @@ -206,7 +206,9 @@ export function LargeButton(props: LargeButtonProps): JSX.Element { border: ${buttonType === 'stroke' ? `2px solid ${COLORS.blue55}` - : `${computedBorderStyle()}`}; + : buttonType === 'primary' + ? `4px solid ${COLORS.blue55}` + : computedBorderStyle()}; } &:focus-visible { From 6c89f59a4ad3e065fad87299cda8419fb39453dd Mon Sep 17 00:00:00 2001 From: koji Date: Thu, 6 Feb 2025 10:29:44 -0500 Subject: [PATCH 12/18] fix(protocol-designer): fix step overflow menu position (#17439) * fix(protocol-designer): fix step overflow menu position --- .../pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx | 1 + .../Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx | 6 +++++- .../Timeline/__tests__/StepOverflowMenu.test.tsx | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx index d0534b234cf..d01a0b60b48 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx @@ -294,6 +294,7 @@ export function StepContainer(props: StepContainerProps): JSX.Element { confirmDelete={confirmDelete} confirmMultiDelete={confirmMultiDelete} multiSelectItemIds={multiSelectItemIds} + sidebarWidth={sidebarWidth} />, getMainPagePortalEl() ) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx index 465e85b577d..4d62c383cca 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx @@ -41,8 +41,11 @@ interface StepOverflowMenuProps { confirmDelete: () => void confirmMultiDelete: () => void multiSelectItemIds: string[] | null + sidebarWidth: number // adjust the position of the overflow menu } +const POSITION_ADJUSTMENT = 4 + export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { const { stepId, @@ -53,6 +56,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { confirmDelete, confirmMultiDelete, multiSelectItemIds, + sidebarWidth, } = props const { t } = useTranslation('protocol_steps') const singleEditFormHasUnsavedChanges = useSelector( @@ -101,7 +105,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { ref={menuRootRef} zIndex={12} top={top} - left="18.75rem" + left={sidebarWidth - POSITION_ADJUSTMENT} // the space between kebab menu button and overflow menu is 8px position={POSITION_ABSOLUTE} whiteSpace={NO_WRAP} borderRadius={BORDERS.borderRadius8} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepOverflowMenu.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepOverflowMenu.test.tsx index 55197e85ed4..93c115e9255 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepOverflowMenu.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepOverflowMenu.test.tsx @@ -67,6 +67,7 @@ describe('StepOverflowMenu', () => { handleEdit: vi.fn(), confirmDelete: mockConfirm, confirmMultiDelete: vi.fn(), + sidebarWidth: 235, } vi.mocked(getMultiSelectItemIds).mockReturnValue(null) vi.mocked(getCurrentFormIsPresaved).mockReturnValue(false) From cea40c2dc781df32d18316afdb937bf717c98449 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 6 Feb 2025 10:39:16 -0500 Subject: [PATCH 13/18] fix(protocol-designer): fix presaved absorbance reader step form type (#17444) Properly preselect absorbance reader form type based on the module state at the creation of that form. The bug here arose from using the initial robot state to determine module state rather than the current robot state. Closes RQA-3943 --- .../src/step-forms/utils/createPresavedStepForm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts index 89474e7cb2f..bea9aca8e53 100644 --- a/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts +++ b/protocol-designer/src/step-forms/utils/createPresavedStepForm.ts @@ -305,10 +305,10 @@ const _patchAbsorbanceReaderModuleId = (args: { )?.length ?? 1 const hasAbsorbanceReaderModuleId = stepType === 'absorbanceReader' - const { modules } = initialDeckSetup const robotState: RobotState | null = last(robotStateTimeline.timeline)?.robotState ?? null + const modules = robotState?.modules ?? {} const labware = robotState?.labware ?? {} // pre-select form type if module is set From 9c70e65be3763659c5fcc4be7e54f777c73cbbe9 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 6 Feb 2025 10:39:36 -0500 Subject: [PATCH 14/18] fix(protocol-designer): various DQA fixes (#17440) This PR provides DQA fixes for 8.4.0 alpha.1. Closes RQA-3929, Closes RQA-3930, Closes RQA-3931, Closes RQA-3933, Closes RQA-3934 --- .../atoms/ListButton/__tests__/ListButton.test.tsx | 2 +- components/src/atoms/ListButton/index.tsx | 4 ++-- .../ProtocolSteps/StepForm/StepFormToolbox.tsx | 2 +- .../AbsorbanceReaderTools/Initialization.tsx | 11 ++++++----- .../ProtocolSteps/Timeline/AddStepOverflowButton.tsx | 2 +- .../ProtocolSteps/Timeline/ConnectedStepInfo.tsx | 5 +++-- .../Timeline/__tests__/AddStepButton.test.tsx | 2 +- .../ProtocolSteps/__tests__/ProtocolSteps.test.tsx | 2 +- .../src/pages/Designer/ProtocolSteps/index.tsx | 2 +- 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/components/src/atoms/ListButton/__tests__/ListButton.test.tsx b/components/src/atoms/ListButton/__tests__/ListButton.test.tsx index fe4e3fb7349..2d65b14c61c 100644 --- a/components/src/atoms/ListButton/__tests__/ListButton.test.tsx +++ b/components/src/atoms/ListButton/__tests__/ListButton.test.tsx @@ -25,7 +25,7 @@ describe('ListButton', () => { it('should render correct style - noActive', () => { render(props) const listButton = screen.getByTestId('ListButton_noActive') - expect(listButton).toHaveStyle(`backgroundColor: ${COLORS.grey30}`) + expect(listButton).toHaveStyle(`backgroundColor: ${COLORS.grey20}`) }) it('should render correct style - connected', () => { props.type = 'connected' diff --git a/components/src/atoms/ListButton/index.tsx b/components/src/atoms/ListButton/index.tsx index 610c76bb7a9..38c1b4845c4 100644 --- a/components/src/atoms/ListButton/index.tsx +++ b/components/src/atoms/ListButton/index.tsx @@ -23,8 +23,8 @@ const LISTBUTTON_PROPS_BY_TYPE: Record< { backgroundColor: string; hoverBackgroundColor: string } > = { noActive: { - backgroundColor: COLORS.grey30, - hoverBackgroundColor: COLORS.grey35, + backgroundColor: COLORS.grey20, + hoverBackgroundColor: COLORS.grey30, }, connected: { backgroundColor: COLORS.green30, diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 253889423ca..bd1dfe04ed2 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx @@ -248,7 +248,7 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { numErrors, stepTypeDisplayName: i18n.format( t(`stepType.${formData.stepType}`), - 'capitalize' + 'titleCase' ), t, }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx index 1b6c5252917..4c8f5a18d76 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx @@ -24,6 +24,7 @@ import { Tooltip, useHoverTooltip, } from '@opentrons/components' +import { LINK_BUTTON_STYLE } from '../../../../../../atoms' import { ABSORBANCE_READER_MAX_WAVELENGTH_NM, ABSORBANCE_READER_MIN_WAVELENGTH_NM, @@ -244,6 +245,7 @@ function IntializationEditor(props: InitializationEditorProps): JSX.Element { text={t('step_edit_form.absorbanceReader.add_wavelength.label')} textAlignment="left" disabled={numWavelengths === MAX_WAVELENGTHS} + iconName="plus" /> ) : null} @@ -337,13 +339,12 @@ function WavelengthItem(props: WavelengthItemProps): JSX.Element { onClick={() => { handleDeleteWavelength(index) }} - alignSelf={ALIGN_FLEX_END} padding={SPACING.spacing4} + css={LINK_BUTTON_STYLE} + alignSelf={ALIGN_FLEX_END} + textDecoration={TEXT_DECORATION_UNDERLINE} > - + {t('step_edit_form.absorbanceReader.delete')} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/AddStepOverflowButton.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/AddStepOverflowButton.tsx index 44b131658f7..1f539ba689e 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/AddStepOverflowButton.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/AddStepOverflowButton.tsx @@ -45,7 +45,7 @@ export function AddStepOverflowButton( {i18n.format( t(`application:stepType.${stepType}`, stepType), - 'capitalize' + 'titleCase' )} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx index 0051499bf15..e044e1e3338 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx @@ -62,7 +62,7 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { setOpenedOverflowMenuId, sidebarWidth, } = props - const { t } = useTranslation('application') + const { i18n, t } = useTranslation('application') const dispatch = useDispatch>() const stepIds = useSelector(getOrderedStepIds) const step = useSelector(stepFormSelectors.getSavedStepForms)[stepId] @@ -227,7 +227,8 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { onMouseEnter={highlightStep} iconName={hasError || hasWarnings ? 'alert-circle' : iconName} title={`${stepNumber}. ${ - step.stepName || t(`stepType.${step.stepType}`) + i18n.format(step.stepName, 'titleCase') || + t(`stepType.${step.stepType}`) }`} dragHovered={dragHovered} sidebarWidth={sidebarWidth} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/AddStepButton.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/AddStepButton.test.tsx index a2fcea0a7e2..69911628b7e 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/AddStepButton.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/AddStepButton.test.tsx @@ -87,7 +87,7 @@ describe('AddStepButton', () => { screen.getByText('Mix') screen.getByText('Pause') screen.getByText('Thermocycler') - screen.getByText('Heater-shaker') + screen.getByText('Heater-Shaker') screen.getByText('Temperature') screen.getByText('Magnet') }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx index d333baf288d..32e1f090baa 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx @@ -115,6 +115,6 @@ describe('ProtocolSteps', () => { it('renders the current step name', () => { render() - screen.getByText('Custom pause') + screen.getByText('Custom Pause') }) }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index 8ef8f52d8e8..0627ca24382 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -120,7 +120,7 @@ export function ProtocolSteps(): JSX.Element { > {currentStep != null && hoveredTerminalItem == null ? ( - {i18n.format(currentStep.stepName, 'capitalize')} + {i18n.format(currentStep.stepName, 'titleCase')} ) : null} {(hoveredTerminalItem != null || selectedTerminalItem != null) && From 78848e5daebec55fb927d35bb78c91fda3e76c51 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 6 Feb 2025 10:40:05 -0500 Subject: [PATCH 15/18] fix(components, protocol-designer): fix design bugs from PD 8.4.0 alpha.1 (#17443) Fix several bugs including 1) properly displaying labware on absorbance reader in absorbance reader step form module options 2) removing the 'delete' button from wavelengths if selected insitialization mode is 'single' Closes RQA-3942, Closes RQA-3945 --- components/src/molecules/DropdownMenu/index.tsx | 2 +- .../StepTools/AbsorbanceReaderTools/Initialization.tsx | 3 ++- protocol-designer/src/ui/modules/selectors.ts | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 276be51511a..4664cdc04b6 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -332,7 +332,7 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { {option.subtext} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx index 4c8f5a18d76..c394627a677 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/AbsorbanceReaderTools/Initialization.tsx @@ -284,6 +284,7 @@ function WavelengthItem(props: WavelengthItemProps): JSX.Element { handleDeleteWavelength, index, error, + mode, } = props const { t } = useTranslation('form') const showCustom = !DEFINED_OPTIONS.some(({ value }) => value === wavelength) @@ -334,7 +335,7 @@ function WavelengthItem(props: WavelengthItemProps): JSX.Element { error={!isFocused ? error : null} /> ) : null} - {wavelengths.length > 1 ? ( + {wavelengths.length > 1 && mode === 'multi' ? ( { handleDeleteWavelength(index) diff --git a/protocol-designer/src/ui/modules/selectors.ts b/protocol-designer/src/ui/modules/selectors.ts index c0b9da78da7..8d5edb5a59b 100644 --- a/protocol-designer/src/ui/modules/selectors.ts +++ b/protocol-designer/src/ui/modules/selectors.ts @@ -8,6 +8,7 @@ import { TEMPERATURE_MODULE_TYPE, } from '@opentrons/shared-data' import { getInitialDeckSetup } from '../../step-forms/selectors' +import { getDeckSetupForActiveItem } from '../../top-selectors/labware-locations' import { getLabwareNicknamesById } from '../labware/selectors' import { getModuleLabwareOptions, @@ -86,11 +87,11 @@ export const getHeaterShakerLabwareOptions: Selector< export const getAbsorbanceReaderLabwareOptions: Selector< DropdownOption[] > = createSelector( - getInitialDeckSetup, + getDeckSetupForActiveItem, getLabwareNicknamesById, - (initialDeckSetup, nicknamesById) => { + (deckSetup, nicknamesById) => { const absorbanceReaderModuleOptions = getModuleLabwareOptions( - initialDeckSetup, + deckSetup, nicknamesById, ABSORBANCE_READER_TYPE ) From a486e17d699782c6c7bf492a4aefa235381dbf3f Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:00:48 -0500 Subject: [PATCH 16/18] fix(components, protocol-designer): fix lineclamp for dropdown menu (#17448) According to designs, the main text for a dropdown option should be clamped to 3 lines maximum. In the event that only one option is produced in DropDownStepFormField, the line clamp should also apply to the returned styled text. Closes RQA-3945 --- .../src/molecules/DropdownMenu/index.tsx | 19 ++++++++++++++----- .../molecules/DropdownStepFormField/index.tsx | 6 +++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 4664cdc04b6..3a367dcf2e4 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -27,6 +27,7 @@ import { LiquidIcon } from '../LiquidIcon' import { DeckInfoLabel } from '../DeckInfoLabel' import type { FocusEventHandler } from 'react' +import type { FlattenSimpleInterpolation } from 'styled-components' export interface DropdownOption { name: string @@ -268,7 +269,7 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { > {currentOption.name} @@ -327,7 +328,10 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { flexDirection={DIRECTION_COLUMN} gridGap={option.subtext != null ? SPACING.spacing4 : '0'} > - + {option.name} css` display: -webkit-box; -webkit-box-orient: vertical; overflow: ${OVERFLOW_HIDDEN}; text-overflow: ellipsis; word-wrap: break-word; - -webkit-line-clamp: 1; - word-break: break-all; + -webkit-line-clamp: ${lineClamp ?? 1}; + word-break: ${title === true + ? 'normal' + : 'break-all'}; // normal for tile and break-all for a non word case like aaaaaaaa ` diff --git a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx index 98ac2d99164..ac6bac171a3 100644 --- a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx +++ b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx @@ -7,6 +7,7 @@ import { DeckInfoLabel, DropdownMenu, Flex, + LINE_CLAMP_TEXT_STYLE, ListItem, SPACING, StyledText, @@ -122,7 +123,10 @@ export function DropdownStepFormField( flexDirection={DIRECTION_COLUMN} gridGap={options[0].subtext != null ? SPACING.spacing4 : '0'} > - + {options[0].name} Date: Thu, 6 Feb 2025 13:16:23 -0500 Subject: [PATCH 17/18] fix(components): add focus-visible style to list button (#17450) * fix(components): add focus-visible style to list button --- components/src/atoms/ListButton/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/src/atoms/ListButton/index.tsx b/components/src/atoms/ListButton/index.tsx index 38c1b4845c4..3125f190ec1 100644 --- a/components/src/atoms/ListButton/index.tsx +++ b/components/src/atoms/ListButton/index.tsx @@ -60,6 +60,11 @@ export function ListButton(props: ListButtonProps): JSX.Element { ? COLORS.grey20 : listButtonProps.hoverBackgroundColor}; } + + &:focus-visible { + outline: 2px solid ${COLORS.blue50}; + outline-offset: 0.25rem; + } ` return ( @@ -67,6 +72,7 @@ export function ListButton(props: ListButtonProps): JSX.Element { data-testid={`ListButton_${type}`} onClick={onClick} css={LIST_BUTTON_STYLE} + tabIndex={0} {...styleProps} > {children} From 09e127d33444c4160b7b48da20001affa2df1302 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:24:53 -0500 Subject: [PATCH 18/18] fix(protocol-designer): fix temperature step form (#17447) This PR fixes a bug in the temperature step form where a form error is incorrecly returned if a user has not entered a temperature, even if the setTemperature ield is set to false. The error arose from incorrectly parsing the string literals for 'true' / 'false'. Also, this PR fixes the step summary text for deactivating a temperature module Closes RQA-3947, RQA-3948 --- .../protocol/8/doItAllV4MigratedToV8.json | 262 ++++-- .../protocol/8/doItAllV7MigratedToV8.json | 861 +++++++++++++----- .../8/newAdvancedSettingsAndMultiTemp.json | 185 +++- .../Designer/ProtocolSteps/StepSummary.tsx | 11 +- .../src/steplist/formLevel/errors.ts | 2 +- 5 files changed, 968 insertions(+), 353 deletions(-) diff --git a/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json b/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json index bf503ff3219..ebc99e3035e 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV4MigratedToV8.json @@ -6,16 +6,16 @@ "author": "Fixture", "description": "Test all v4 commands", "created": 1585930833548, - "lastModified": 1731344437355, + "lastModified": 1738865145181, "category": null, "subcategory": null, "tags": [] }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.0", + "version": "8.4.0-alpha.1", "data": { - "_internalAppBuildDate": "Mon, 11 Nov 2024 16:56:05 GMT", + "_internalAppBuildDate": "Thu, 06 Feb 2025 16:23:43 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, "dispense_mmFromBottom": 1, @@ -27,7 +27,10 @@ "opentrons/opentrons_96_tiprack_300ul/1" ] }, - "dismissedWarnings": { "form": [], "timeline": [] }, + "dismissedWarnings": { + "form": [], + "timeline": [] + }, "ingredients": { "0": { "name": "Water", @@ -38,22 +41,86 @@ }, "ingredLocations": { "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { - "A1": { "0": { "volume": 100 } }, - "B1": { "0": { "volume": 100 } }, - "C1": { "0": { "volume": 100 } }, - "D1": { "0": { "volume": 100 } }, - "E1": { "0": { "volume": 100 } }, - "F1": { "0": { "volume": 100 } }, - "G1": { "0": { "volume": 100 } }, - "H1": { "0": { "volume": 100 } }, - "A2": { "0": { "volume": 100 } }, - "B2": { "0": { "volume": 100 } }, - "C2": { "0": { "volume": 100 } }, - "D2": { "0": { "volume": 100 } }, - "E2": { "0": { "volume": 100 } }, - "F2": { "0": { "volume": 100 } }, - "G2": { "0": { "volume": 100 } }, - "H2": { "0": { "volume": 100 } } + "A1": { + "0": { + "volume": 100 + } + }, + "B1": { + "0": { + "volume": 100 + } + }, + "C1": { + "0": { + "volume": 100 + } + }, + "D1": { + "0": { + "volume": 100 + } + }, + "E1": { + "0": { + "volume": 100 + } + }, + "F1": { + "0": { + "volume": 100 + } + }, + "G1": { + "0": { + "volume": 100 + } + }, + "H1": { + "0": { + "volume": 100 + } + }, + "A2": { + "0": { + "volume": 100 + } + }, + "B2": { + "0": { + "volume": 100 + } + }, + "C2": { + "0": { + "volume": 100 + } + }, + "D2": { + "0": { + "volume": 100 + } + }, + "E2": { + "0": { + "volume": 100 + } + }, + "F2": { + "0": { + "volume": 100 + } + }, + "G2": { + "0": { + "volume": 100 + } + }, + "H2": { + "0": { + "volume": 100 + } + } } }, "savedStepForms": { @@ -124,7 +191,7 @@ "aspirate_y_position": 0, "blowout_checkbox": false, "blowout_flowRate": null, - "blowout_location": "167531be-c08f-48d1-94d1-f71903140c6d:trashBin", + "blowout_location": "be737bc2-9736-457a-9a8c-7277546f8a1f:trashBin", "blowout_z_offset": 0, "changeTip": "always", "dispense_airGap_checkbox": false, @@ -147,7 +214,7 @@ "dispense_y_position": 0, "disposalVolume_checkbox": true, "disposalVolume_volume": "20", - "dropTip_location": "167531be-c08f-48d1-94d1-f71903140c6d:trashBin", + "dropTip_location": "be737bc2-9736-457a-9a8c-7277546f8a1f:trashBin", "nozzles": null, "path": "single", "pipette": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", @@ -212,7 +279,10 @@ ] } }, - "robot": { "model": "OT-2 Standard", "deckId": "ot2_standard" }, + "robot": { + "model": "OT-2 Standard", + "deckId": "ot2_standard" + }, "labwareDefinitionSchemaId": "opentronsLabwareSchemaV2", "labwareDefinitions": { "opentrons/opentrons_96_tiprack_300ul/1": { @@ -1228,7 +1298,11 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } }, "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1": { "ordering": [ @@ -2129,7 +2203,9 @@ }, "groups": [ { - "metadata": { "wellBottomShape": "v" }, + "metadata": { + "wellBottomShape": "v" + }, "wells": [ "A1", "B1", @@ -2240,7 +2316,11 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } }, "opentrons/opentrons_24_aluminumblock_generic_2ml_screwcap/1": { "ordering": [ @@ -2529,10 +2609,18 @@ "displayCategory": "tubeRack", "wellBottomShape": "v" }, - "brand": { "brand": "generic", "brandId": [], "links": [] } + "brand": { + "brand": "generic", + "brandId": [], + "links": [] + } } ], - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } } }, "liquidSchemaId": "opentronsLiquidSchemaV1", @@ -2546,7 +2634,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "9dc2bc3a-d168-4d1d-b0fd-d245d40ec098", + "key": "4863af21-c51a-4773-836e-69d2b5e37260", "commandType": "loadPipette", "params": { "pipetteName": "p300_single_gen2", @@ -2555,25 +2643,29 @@ } }, { - "key": "b82bae59-895e-4bd7-b99a-6cc71194ee8b", + "key": "d50f8c64-3748-42ab-93c4-a81a62dfe5de", "commandType": "loadModule", "params": { "model": "magneticModuleV2", - "location": { "slotName": "1" }, + "location": { + "slotName": "1" + }, "moduleId": "0b419310-75c7-11ea-b42f-4b64e50f43e5:magneticModuleType" } }, { - "key": "60abede1-fbec-4bf1-8391-aea766f2a47f", + "key": "433c2f7d-ad0a-4490-ab26-03b3951ace37", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", - "location": { "slotName": "3" }, + "location": { + "slotName": "3" + }, "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType" } }, { - "key": "60e77a8c-b589-4c8d-beee-0c523990ea16", + "key": "93d70768-06a8-4be1-a6f7-28692f843c4f", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Tip Rack 300 µL", @@ -2581,11 +2673,13 @@ "loadName": "opentrons_96_tiprack_300ul", "namespace": "opentrons", "version": 1, - "location": { "slotName": "2" } + "location": { + "slotName": "2" + } } }, { - "key": "c9e0ed1a-393a-4e24-9c38-09dbd077b1f4", + "key": "5700b9ac-2cda-4655-b343-cef9488e8432", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -2599,7 +2693,7 @@ } }, { - "key": "3ece81f9-ab9e-45e2-983b-313f4590d1de", + "key": "92a14954-b618-4010-b969-fda49cd2f86a", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with Generic 2 mL Screwcap", @@ -2614,7 +2708,7 @@ }, { "commandType": "loadLiquid", - "key": "75a3d767-5bd8-4e53-bb21-c4ebf5fd5fa4", + "key": "0f0e3f43-011d-4567-906e-d50a95430093", "params": { "liquidId": "0", "labwareId": "1e610d40-75c7-11ea-b42f-4b64e50f43e5:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/1", @@ -2640,7 +2734,7 @@ }, { "commandType": "magneticModule/engage", - "key": "59f8a733-9ff9-48e9-8d96-f9eda394b2d6", + "key": "1eb5f632-3710-4204-b732-79c10e781089", "params": { "moduleId": "0b419310-75c7-11ea-b42f-4b64e50f43e5:magneticModuleType", "height": 6 @@ -2648,7 +2742,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "14f776bf-8090-44bd-a5a7-6a9dc5de83e4", + "key": "593db0b0-aefa-4c01-a385-f5de6caaaccf", "params": { "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType", "celsius": 25 @@ -2656,12 +2750,15 @@ }, { "commandType": "waitForDuration", - "key": "89c7051a-2e03-4540-aa68-230b4aa2fa73", - "params": { "seconds": 62, "message": "" } + "key": "90fad6fa-dcab-4152-892c-a6bfc5605af0", + "params": { + "seconds": 62, + "message": "" + } }, { "commandType": "pickUpTip", - "key": "f93df8a3-60cf-4757-9f84-1919a4c08ad8", + "key": "d76bb9fd-4b69-4e63-a8e0-b73fb0dba814", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2670,7 +2767,7 @@ }, { "commandType": "aspirate", - "key": "06deecf7-7e2e-4634-b421-ac4aa34f7dd6", + "key": "7167ca75-7f59-4dd2-ab58-5189b698ddab", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2678,14 +2775,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 46.43 } }, { "commandType": "dispense", - "key": "19ea41bb-b586-4890-9066-c1b52bb36b1c", + "key": "bde65b9f-dbe5-4e66-821c-efbcf33c0d96", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2693,29 +2794,39 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 46.43 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "024b2758-3aeb-43c0-83ed-31968d312eb3", + "key": "d82ece32-e7b5-4395-8b12-864f1e5b826c", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "eff8e3c5-29cc-45d2-a9fa-9e387f8c47e4", - "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } + "key": "2f0cdf72-7a58-431c-9bd1-b2e78951f3a9", + "params": { + "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" + } }, { "commandType": "pickUpTip", - "key": "d88115a0-7736-45d1-9d06-c0ea94f11635", + "key": "8882cb77-8de2-4eda-aa8c-b08c157071ab", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "labwareId": "0b44c760-75c7-11ea-b42f-4b64e50f43e5:opentrons/opentrons_96_tiprack_300ul/1", @@ -2724,7 +2835,7 @@ }, { "commandType": "aspirate", - "key": "6144ee81-8b1d-4cef-a35a-7b213d3b8a8c", + "key": "7f038375-cb26-463d-a684-de11bb6cb3df", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2732,14 +2843,18 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 46.43 } }, { "commandType": "dispense", - "key": "da3aaaa3-1e5d-4492-8763-97b696119450", + "key": "f67e1305-295f-4de9-89e9-ae2a472e74bd", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "volume": 30, @@ -2747,29 +2862,39 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 46.43 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "2168d24b-a738-4505-925e-8285ae6ac620", + "key": "58760b05-917c-46cd-aa72-b17223124a53", "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5", "addressableAreaName": "fixedTrash", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "91da0a46-1eed-4bbc-a428-c9bd9e8ca8c4", - "params": { "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" } + "key": "c24b3e14-aac9-49e8-9bdc-7b47be308fd8", + "params": { + "pipetteId": "0b3f2210-75c7-11ea-b42f-4b64e50f43e5" + } }, { "commandType": "temperatureModule/waitForTemperature", - "key": "b3bf1b53-015d-4141-b5b9-a03a265d9991", + "key": "86ae5fcd-8176-4206-8b06-64e8fb5ed3fa", "params": { "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType", "celsius": 25 @@ -2777,15 +2902,24 @@ }, { "commandType": "magneticModule/disengage", - "key": "94500510-1a75-425a-a6c4-2a89c9ed1b50", + "key": "2d63adb8-0085-44cd-93de-dbb86497b298", "params": { "moduleId": "0b419310-75c7-11ea-b42f-4b64e50f43e5:magneticModuleType" } }, { "commandType": "waitForResume", - "key": "993f2eaf-7348-4a29-be1c-61612a353639", - "params": { "message": "Wait until user intervention" } + "key": "1ef4fb78-d099-41a6-b8a3-da9d0d654e86", + "params": { + "message": "Wait until user intervention" + } + }, + { + "commandType": "temperatureModule/deactivate", + "key": "9500369f-9575-4664-92d5-2e30e44e582d", + "params": { + "moduleId": "0b4319b0-75c7-11ea-b42f-4b64e50f43e5:temperatureModuleType" + } } ], "commandAnnotationSchemaId": "opentronsCommandAnnotationSchemaV1", diff --git a/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json b/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json index 4ba403c4590..6a18a3bfa90 100644 --- a/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json +++ b/protocol-designer/fixtures/protocol/8/doItAllV7MigratedToV8.json @@ -6,16 +6,16 @@ "author": "", "description": "", "created": 1689346890165, - "lastModified": 1731344479074, + "lastModified": 1738863904063, "category": null, "subcategory": null, "tags": [] }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.0", + "version": "8.4.0-alpha.1", "data": { - "_internalAppBuildDate": "Mon, 11 Nov 2024 16:56:05 GMT", + "_internalAppBuildDate": "Thu, 06 Feb 2025 16:23:43 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, "dispense_mmFromBottom": 1, @@ -30,7 +30,10 @@ "opentrons/opentrons_flex_96_filtertiprack_50ul/1" ] }, - "dismissedWarnings": { "form": [], "timeline": [] }, + "dismissedWarnings": { + "form": [], + "timeline": [] + }, "ingredients": { "0": { "name": "Water", @@ -49,17 +52,53 @@ }, "ingredLocations": { "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2": { - "A1": { "0": { "volume": 100 } }, - "B1": { "0": { "volume": 100 } }, - "C1": { "0": { "volume": 100 } }, - "D1": { "0": { "volume": 100 } }, - "E1": { "0": { "volume": 100 } }, - "F1": { "0": { "volume": 100 } }, - "G1": { "0": { "volume": 100 } }, - "H1": { "0": { "volume": 100 } } + "A1": { + "0": { + "volume": 100 + } + }, + "B1": { + "0": { + "volume": 100 + } + }, + "C1": { + "0": { + "volume": 100 + } + }, + "D1": { + "0": { + "volume": 100 + } + }, + "E1": { + "0": { + "volume": 100 + } + }, + "F1": { + "0": { + "volume": 100 + } + }, + "G1": { + "0": { + "volume": 100 + } + }, + "H1": { + "0": { + "volume": 100 + } + } }, "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1": { - "A1": { "1": { "volume": 1000 } } + "A1": { + "1": { + "volume": 1000 + } + } } }, "savedStepForms": { @@ -170,7 +209,7 @@ "aspirate_y_position": 0, "blowout_checkbox": false, "blowout_flowRate": null, - "blowout_location": "d5e65ebb-318b-4c78-8fc8-770b1d6100dc:trashBin", + "blowout_location": "915efe52-0d59-43ee-a8d0-eb6b21a52118:trashBin", "blowout_z_offset": 0, "changeTip": "always", "dispense_airGap_checkbox": false, @@ -193,7 +232,7 @@ "dispense_y_position": 0, "disposalVolume_checkbox": true, "disposalVolume_volume": "100", - "dropTip_location": "d5e65ebb-318b-4c78-8fc8-770b1d6100dc:trashBin", + "dropTip_location": "915efe52-0d59-43ee-a8d0-eb6b21a52118:trashBin", "nozzles": null, "path": "single", "pipette": "2e7c6344-58ab-465c-b542-489883cb63fe", @@ -211,13 +250,13 @@ "aspirate_flowRate": null, "blowout_checkbox": false, "blowout_flowRate": null, - "blowout_location": "d5e65ebb-318b-4c78-8fc8-770b1d6100dc:trashBin", + "blowout_location": "915efe52-0d59-43ee-a8d0-eb6b21a52118:trashBin", "blowout_z_offset": 0, "changeTip": "always", "dispense_delay_checkbox": false, "dispense_delay_seconds": "1", "dispense_flowRate": null, - "dropTip_location": "d5e65ebb-318b-4c78-8fc8-770b1d6100dc:trashBin", + "dropTip_location": "915efe52-0d59-43ee-a8d0-eb6b21a52118:trashBin", "labware": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "mix_mmFromBottom": 0.5, "mix_touchTip_checkbox": false, @@ -360,7 +399,10 @@ ] } }, - "robot": { "model": "OT-3 Standard", "deckId": "ot3_standard" }, + "robot": { + "model": "OT-3 Standard", + "deckId": "ot3_standard" + }, "labwareDefinitionSchemaId": "opentronsLabwareSchemaV2", "labwareDefinitions": { "opentrons/opentrons_flex_96_filtertiprack_50ul/1": { @@ -378,7 +420,10 @@ ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] ], - "brand": { "brand": "Opentrons", "brandId": [] }, + "brand": { + "brand": "Opentrons", + "brandId": [] + }, "metadata": { "displayName": "Opentrons Flex 96 Filter Tip Rack 50 µL", "displayCategory": "tipRack", @@ -1373,23 +1418,43 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { "x": 0, "y": 0, "z": 121 } + "opentrons_flex_96_tiprack_adapter": { + "x": 0, + "y": 0, + "z": 121 + } } }, "opentrons/opentrons_96_flat_bottom_adapter/1": { "ordering": [], - "brand": { "brand": "Opentrons", "brandId": [] }, + "brand": { + "brand": "Opentrons", + "brandId": [] + }, "metadata": { "displayName": "Opentrons 96 Flat Bottom Heater-Shaker Adapter", "displayCategory": "adapter", "displayVolumeUnits": "µL", "tags": [] }, - "dimensions": { "xDimension": 111, "yDimension": 75, "zDimension": 7.9 }, + "dimensions": { + "xDimension": 111, + "yDimension": 75, + "zDimension": 7.9 + }, "wells": {}, - "groups": [{ "metadata": {}, "wells": [] }], + "groups": [ + { + "metadata": {}, + "wells": [] + } + ], "parameters": { "format": "96Standard", "quirks": [], @@ -1401,7 +1466,11 @@ "version": 1, "schemaVersion": 2, "allowedRoles": ["adapter"], - "cornerOffsetFromSlot": { "x": 8.5, "y": 5.5, "z": 0 } + "cornerOffsetFromSlot": { + "x": 8.5, + "y": 5.5, + "z": 0 + } }, "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2": { "ordering": [ @@ -2304,7 +2373,9 @@ }, "groups": [ { - "metadata": { "wellBottomShape": "v" }, + "metadata": { + "wellBottomShape": "v" + }, "wells": [ "A1", "B1", @@ -2415,13 +2486,29 @@ "namespace": "opentrons", "version": 2, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "stackingOffsetWithLabware": { - "opentrons_96_pcr_adapter": { "x": 0, "y": 0, "z": 10.2 }, - "opentrons_96_well_aluminum_block": { "x": 0, "y": 0, "z": 12.66 } + "opentrons_96_pcr_adapter": { + "x": 0, + "y": 0, + "z": 10.2 + }, + "opentrons_96_well_aluminum_block": { + "x": 0, + "y": 0, + "z": 12.66 + } }, "stackingOffsetWithModule": { - "thermocyclerModuleV2": { "x": 0, "y": 0, "z": 10.8 } + "thermocyclerModuleV2": { + "x": 0, + "y": 0, + "z": 10.8 + } } }, "opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1": { @@ -2719,7 +2806,11 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } }, "opentrons/nest_96_wellplate_200ul_flat/2": { "ordering": [ @@ -3624,7 +3715,9 @@ }, "groups": [ { - "metadata": { "wellBottomShape": "flat" }, + "metadata": { + "wellBottomShape": "flat" + }, "wells": [ "A1", "B1", @@ -3734,10 +3827,22 @@ "namespace": "opentrons", "version": 2, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "stackingOffsetWithLabware": { - "opentrons_96_flat_bottom_adapter": { "x": 0, "y": 0, "z": 6.7 }, - "opentrons_aluminum_flat_bottom_plate": { "x": 0, "y": 0, "z": 5.55 } + "opentrons_96_flat_bottom_adapter": { + "x": 0, + "y": 0, + "z": 6.7 + }, + "opentrons_aluminum_flat_bottom_plate": { + "x": 0, + "y": 0, + "z": 5.55 + } } } }, @@ -3757,7 +3862,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "887aee95-507e-4e12-befb-fca0df6acd5b", + "key": "eea399e6-ccb5-4c81-9434-806b4694d527", "commandType": "loadPipette", "params": { "pipetteName": "p1000_single_flex", @@ -3766,7 +3871,7 @@ } }, { - "key": "ef8f7d50-4fb2-42fc-96b2-1b09825f5de3", + "key": "010dd483-9b2a-4cac-a259-db760618822b", "commandType": "loadPipette", "params": { "pipetteName": "p50_multi_flex", @@ -3775,43 +3880,51 @@ } }, { - "key": "29625abf-a695-48ad-ae3f-74a484e5ed9b", + "key": "42e76ead-cc5a-4a80-b9bc-92befe08b0cd", "commandType": "loadModule", "params": { "model": "magneticBlockV1", - "location": { "slotName": "D2" }, + "location": { + "slotName": "D2" + }, "moduleId": "1be16305-74e7-4bdb-9737-61ec726d2b44:magneticBlockType" } }, { - "key": "1ac087ae-c74a-4817-878d-98bdf3db848a", + "key": "825a1f74-b93e-49b8-a96e-2d71268c695e", "commandType": "loadModule", "params": { "model": "heaterShakerModuleV1", - "location": { "slotName": "D1" }, + "location": { + "slotName": "D1" + }, "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { - "key": "92265fb4-87cf-4602-baf1-a1e42abf72b3", + "key": "ea872f2f-53a9-4619-ae77-01fb965ecd97", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", - "location": { "slotName": "D3" }, + "location": { + "slotName": "D3" + }, "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType" } }, { - "key": "8ad9c496-dc5a-46dc-aabe-51917185f007", + "key": "e8855b1c-77d5-4e2c-815d-a633adf46b9a", "commandType": "loadModule", "params": { "model": "thermocyclerModuleV2", - "location": { "slotName": "B1" }, + "location": { + "slotName": "B1" + }, "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { - "key": "892a61fd-b3ba-44c8-8404-811992894b80", + "key": "e7bd4cf3-658d-475f-b757-80e80db59a00", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Flat Bottom Heater-Shaker Adapter", @@ -3825,7 +3938,7 @@ } }, { - "key": "1ac6ba82-46d4-416e-a8b0-11c0fecf9140", + "key": "8fe42720-f139-4318-acb0-8fe014ef2c6a", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Filter Tip Rack 50 µL", @@ -3833,11 +3946,13 @@ "loadName": "opentrons_flex_96_filtertiprack_50ul", "namespace": "opentrons", "version": 1, - "location": { "slotName": "C1" } + "location": { + "slotName": "C1" + } } }, { - "key": "980857c6-a7d8-45e6-8288-7b046e10ac3e", + "key": "5c593236-901d-46d3-9035-17a92bffb6aa", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -3851,7 +3966,7 @@ } }, { - "key": "dbe0a5ac-1af4-4002-8abb-8f525d2ddb68", + "key": "fd53a9fa-affe-4f0d-af4a-ac4cce388a70", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap", @@ -3865,7 +3980,7 @@ } }, { - "key": "9751e295-7340-4f63-bdb2-b906a2d7b533", + "key": "b7167a1f-5aac-4b34-9075-8492db08cfb9", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 200 µL Flat", @@ -3880,16 +3995,18 @@ }, { "commandType": "loadLiquid", - "key": "0af3791b-6921-4c06-a79d-227342db1d93", + "key": "21a0a274-d065-4f01-a682-7d9442f88e9a", "params": { "liquidId": "1", "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", - "volumeByWell": { "A1": 1000 } + "volumeByWell": { + "A1": 1000 + } } }, { "commandType": "loadLiquid", - "key": "08e9de43-643d-48bd-a9d9-2d5df8685ffd", + "key": "81010f65-6daa-47bc-a09c-22957cc981b0", "params": { "liquidId": "0", "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", @@ -3907,7 +4024,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "db0ef747-eb15-4392-a794-f0d1e4dbccda", + "key": "293215f8-045a-4f85-b7f3-db38b9558588", "params": { "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType", "celsius": 4 @@ -3915,7 +4032,7 @@ }, { "commandType": "heaterShaker/waitForTemperature", - "key": "4aacf1f1-deeb-4b2a-9000-c0280faa4687", + "key": "35059006-b3d1-4b7f-b0e7-c4d19507ec82", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "celsius": 4 @@ -3923,14 +4040,14 @@ }, { "commandType": "thermocycler/closeLid", - "key": "7c7d8790-6b8e-47f5-8fe4-8a752646bb48", + "key": "3ac43268-6e08-4ead-883e-86758936af0a", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/setTargetLidTemperature", - "key": "3d4b0df9-e2db-4a47-9cb5-78965dfd53df", + "key": "4326ef19-b928-4081-92d9-82db448feace", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "celsius": 40 @@ -3938,47 +4055,53 @@ }, { "commandType": "thermocycler/waitForLidTemperature", - "key": "df7b47c3-4a1d-417e-8148-114eff720a7e", + "key": "32300d93-5029-45d6-8738-ca1863a2ec3a", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/runProfile", - "key": "749ef412-772e-4df5-b9f5-6611d50b7a36", + "key": "d53d3b22-05e5-4c7e-a2b6-4b660d543406", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType", "profile": [ - { "holdSeconds": 60, "celsius": 4 }, - { "holdSeconds": 120, "celsius": 10 } + { + "holdSeconds": 60, + "celsius": 4 + }, + { + "holdSeconds": 120, + "celsius": 10 + } ], "blockMaxVolumeUl": 10 } }, { "commandType": "thermocycler/deactivateBlock", - "key": "8ad948e1-d18b-4f79-a8bf-1ab607656b36", + "key": "79860cf1-0bbc-4c62-89fd-227d45954273", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/deactivateLid", - "key": "69de8a1f-6790-4a4d-afe9-35b4c39068a1", + "key": "edaafd5b-d279-4247-ba03-c704ce3afa83", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "thermocycler/openLid", - "key": "492b24b0-11c5-4bcb-9ae7-5eede69948a5", + "key": "a17e190a-5a33-420c-8fa0-13ecf73a2ea7", "params": { "moduleId": "627b7a27-5bb7-46de-a530-67af45652e3b:thermocyclerModuleType" } }, { "commandType": "pickUpTip", - "key": "48daaa83-b255-47e7-8153-3877b8e6f07e", + "key": "334c4204-c514-4218-85ba-3d56528f45a8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -3987,7 +4110,7 @@ }, { "commandType": "aspirate", - "key": "270b0416-b790-4e2d-b1c1-8936d6208471", + "key": "e93df5c7-c764-4016-b3dc-e834c643cf70", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -3995,14 +4118,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "055f0831-391f-44f4-a948-cc9219d9afa8", + "key": "5cc286e6-24ef-4ba4-9482-3629c2ab885d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4010,29 +4137,39 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "1d2ab878-315f-4b7d-9f4f-2c8ea6a97fe2", + "key": "3afb7d37-945d-4e3a-9602-86eebdd5fbd6", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "94fb65ce-697c-49b5-bc4e-fb0cc3500007", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "33c88c45-3128-48ab-b8de-0defd3068e6f", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "764e4c75-458a-4d8f-9a7f-e9d63da2cbc5", + "key": "99165960-dd3b-4b6d-95a7-4752d1610c32", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4041,7 +4178,7 @@ }, { "commandType": "aspirate", - "key": "dc4fd07a-a653-4bd7-bf7e-43ab5e24b80d", + "key": "e371c03f-b07e-40d1-beae-b875755250dc", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4049,14 +4186,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "eb6976b2-6b88-40fc-a0b7-ad72d959fe7e", + "key": "d6a8e6ee-df5a-4ad7-96be-2cbab3f7f755", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4064,29 +4205,39 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "0a696e1d-e207-49d0-875a-a10b50ed1f5a", + "key": "76327a5e-3559-490f-a245-2a0a43590d50", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "b39fa5a0-63dc-4cc7-92ce-828b345324ef", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "aac8c10d-f5dd-45a6-abd8-1e784e14219a", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "06ef1868-96d0-4dd1-b85e-167da4ea05f0", + "key": "099c1aac-1cca-429d-b58f-d031c1ff055a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4095,7 +4246,7 @@ }, { "commandType": "aspirate", - "key": "8d957583-f0ba-4799-9fb7-5bb73fefcf75", + "key": "9c83f631-a8ff-4057-b2d4-ef2f8fb52717", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4103,14 +4254,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "bc58797b-31ae-4b87-829b-84f9b5c5446e", + "key": "2a7e1dba-04ad-4b1b-b7d4-ae9112ef8dae", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4118,29 +4273,39 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "c2f0bccf-03b1-4069-8b95-3657b32d841f", + "key": "8be58b57-038a-4c8c-af5c-d4b4dd10a31b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "e14328bc-0b63-48e4-99ad-43be80f4fd2d", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "bac9cf2f-baac-4d87-a5cc-e9e3e1444e87", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "3f605100-7eed-467b-8783-8ffdcf9b7fa7", + "key": "56f5f41f-f370-499c-be69-3e7f8fcda5c7", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4149,7 +4314,7 @@ }, { "commandType": "aspirate", - "key": "8bfe3f3f-265f-4efe-b15a-2f514518bcef", + "key": "22dc4b24-2e2e-4d4c-92ea-2900b0e542b8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4157,14 +4322,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "03a5fc4d-da4c-4a35-9b83-43c098b89fbe", + "key": "d7b7b074-c6f2-4a06-9a66-64cc0b18f473", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4172,29 +4341,39 @@ "wellName": "B1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "02f8b32b-f284-45b9-a87c-9fbebd0a9643", + "key": "7d2bc8e9-8c9d-4b50-9157-053a9f9599b1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "ed9a198d-8be1-4633-91ff-2b2a3d76d42c", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "dfda68dd-03c0-4c8d-a2a1-290d2986a4f4", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "f191fabd-2496-40cb-a7d6-8f3ec117d115", + "key": "bb6000f7-2b94-4f87-a8dc-46b32473f7de", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4203,7 +4382,7 @@ }, { "commandType": "aspirate", - "key": "8a354f35-1aa1-4a96-b0ea-67411d21cb2c", + "key": "713f3bff-41ee-4034-aa67-bc48763f4ffe", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4211,14 +4390,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "b44e4449-c28e-4aae-b269-a1d382634a98", + "key": "48064712-5cbd-485a-97e1-0d50d7a8ff30", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4226,29 +4409,39 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "d81b7400-11c0-458b-b18e-6fe0c2eda148", + "key": "18bcf859-2dc0-410c-97b1-8091451330bc", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "51c547bd-a33f-47b8-8d83-6bbe3bcd100e", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "cbb49d1a-95c6-48ed-b204-7b9174080006", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "18d87e96-962d-4d43-802d-aee8b786485e", + "key": "e52e10fe-ce4b-4850-b1db-00b37c3d01a8", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4257,7 +4450,7 @@ }, { "commandType": "aspirate", - "key": "2f67c8b4-3946-4270-951a-ef0615cd350c", + "key": "534773ab-5ba4-4de4-9a51-f131609b20d1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4265,14 +4458,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "0120cb1c-3610-43f6-b521-529aea32b8ac", + "key": "5cf5b356-d597-4c28-b7d3-7891620e37a3", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4280,29 +4477,39 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "de434c5e-7d65-4c86-9f0e-faa91e81f8cc", + "key": "a0e605f6-fb41-4598-b563-cedde6812232", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "337efcb1-c1ad-4564-9ac3-c626c222ffe8", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "12157169-a6c6-43a5-953e-62c38db69996", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "df4d642a-bab5-4dd4-94c1-cca74d57d7b4", + "key": "05842b52-1212-4aee-b608-d557ca335ef0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4311,7 +4518,7 @@ }, { "commandType": "aspirate", - "key": "02e1ddb4-50b7-4578-b79d-7b4e3e14ffe6", + "key": "547cc238-8a7d-43ff-83e9-46d7f1ab735f", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4319,14 +4526,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "493e252e-258d-4a2e-88ff-5c78373cbdd9", + "key": "bb6cf045-ccd2-410a-8ff7-9c8fea35a682", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4334,29 +4545,39 @@ "wellName": "D1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "4c580d3a-6195-4782-a7c0-ea8967887ba9", + "key": "bb3acf40-6dfe-46d8-a91f-4a6422b1b81b", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "50839851-407c-47a7-83ff-0f8d776c5114", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "30d62f2f-17ab-48b6-a3d4-86012827c7bf", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "da3ab40c-1e79-4a12-96b0-912fd05e3cfa", + "key": "7f6731c8-0a1a-4ca1-b44e-94dcf4618e65", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4365,7 +4586,7 @@ }, { "commandType": "aspirate", - "key": "890aa1c0-86c4-489c-8c67-6b4713d8a926", + "key": "cc92f931-9303-4739-95b6-5d04acbde6f0", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4373,14 +4594,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "17b87840-4838-43d9-ae4e-7466423dd94c", + "key": "e2bbb643-4978-43d7-b48d-8336bd910dad", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4388,29 +4613,39 @@ "wellName": "D1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "9c3a705f-97cf-40cc-99f2-9b1629f76c47", + "key": "26291d38-f0ad-4afa-b9ed-246f049ece91", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "1621491e-e703-421a-8d72-244f4d916eef", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "15848f84-fdf7-4129-9306-e6223aa3674f", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "604c0c35-ef7a-4d97-9cd2-d2ceacdb3a79", + "key": "65683e6b-09c8-447c-a83a-71b67040cd22", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4419,7 +4654,7 @@ }, { "commandType": "aspirate", - "key": "9beb1dba-1af3-4de5-a435-c9ce2e803a1f", + "key": "4a5a3bd4-4763-4792-ad9c-b9b70765b29e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4427,14 +4662,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "ec47755c-f777-4a67-a7e4-88e3c5dc079f", + "key": "81b0257a-f1c1-44a4-a335-902c1cee67b3", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4442,29 +4681,39 @@ "wellName": "E1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "130577d9-f904-460f-b0d8-8906c3208ba5", + "key": "f498eb57-b2d4-418e-903d-818f1d709941", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "fd629662-f71d-4d06-8731-b9a1c4b86240", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "1decbbe3-4181-418e-9529-70ebdbdb45fe", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "a73b0c2e-2cb2-48ae-8aa2-884c9c38ced4", + "key": "4a9d4adf-0f25-403e-b9ae-28f625c8ea55", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4473,7 +4722,7 @@ }, { "commandType": "aspirate", - "key": "b48548ce-b630-4923-a47d-1168bfd99bc3", + "key": "4d6b5147-c02b-44ea-9ebd-ad05da3e7827", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4481,14 +4730,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "869ef98e-183c-404f-ab56-0239836a53bc", + "key": "f73fd947-b49b-43df-94d3-e418f17bad80", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4496,29 +4749,39 @@ "wellName": "E1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "1eb6b94f-b928-4ae2-b54d-60a6ad685261", + "key": "0b2ff5e6-2015-465f-8791-66579959ae27", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "d451de07-77c8-4447-9bee-6e02ecb6c9a8", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "6d777d40-c831-45cb-9e6e-cda470ad7bcd", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "e3b57c34-8862-488f-882a-a6c0ed3aab91", + "key": "13dc6cf7-eb96-4afb-be77-7a28abfdd1b9", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4527,7 +4790,7 @@ }, { "commandType": "aspirate", - "key": "7bfcee1f-c539-4f71-86fd-2a4ce45e72c5", + "key": "757a5f00-63ad-43b3-9334-7980a2459c51", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4535,14 +4798,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "1933daa4-0769-4b1a-85a3-662009a08ff3", + "key": "42930c57-ff1a-48bc-8cd0-ee005e352994", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4550,29 +4817,39 @@ "wellName": "F1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "be69e705-e90b-45ba-b80a-d750a69fbf00", + "key": "4d76096a-9a03-4f91-8de4-6da83748e6c5", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "f70cf632-8b51-425d-b038-8a15ff2646bd", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "0ebd26c3-b1cb-4bab-b650-f449554dc75a", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "70420b51-c232-4a9a-b7f8-b71ae7d1c44a", + "key": "5d7e4382-95b7-47a1-9513-6242cb16fce2", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4581,7 +4858,7 @@ }, { "commandType": "aspirate", - "key": "a4a03e0f-a624-4a2e-8474-4ce0e584c692", + "key": "78b31f64-810b-43e7-b5b1-ad580b84390d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4589,14 +4866,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "21151169-b36b-47bf-ad6a-6d736975b965", + "key": "ad7a11ea-c220-4f21-b935-05053d2bf1fb", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4604,29 +4885,39 @@ "wellName": "F1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "3ec664a4-e16e-47db-8165-f77243dc94ee", + "key": "7130fa8c-6050-4df6-a248-315164298bdd", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "7d14859f-aa90-4eb7-847f-3dfd0bb38ad6", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "5099914c-4b85-4af0-be5a-845bffbeea57", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "49a3b10f-2a40-4564-9663-183f915f065f", + "key": "bde1680d-87c8-4140-9970-48f0e7bad481", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4635,7 +4926,7 @@ }, { "commandType": "aspirate", - "key": "9fde5527-9494-4db3-83a7-87fe9dc4d8f9", + "key": "578cc09e-620b-4d07-8467-7aa4a6da4749", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4643,14 +4934,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "f4cdf6e2-b8b6-44be-8979-ba02dba58dca", + "key": "f9f066ef-4721-489b-9eef-42a47e4f5bd6", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4658,29 +4953,39 @@ "wellName": "G1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "3349573e-f925-4505-8223-5281cd79131e", + "key": "6e952e6d-ae76-4538-97f0-9e65a9d98cf5", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "634d3638-535c-4dd9-8544-bc01a293699c", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "e99dca9b-8696-40c1-aafb-dabf19a98240", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "8fcca86a-4d50-4546-98ac-8af62f0d0650", + "key": "bf2c89a3-3538-4949-a95e-110e79ad9b34", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4689,7 +4994,7 @@ }, { "commandType": "aspirate", - "key": "6a74770f-dca5-4819-8af5-4d322616aef9", + "key": "5f7cd8a0-a3ce-48f7-94ee-37685584255d", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4697,14 +5002,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "eb283f45-95a1-414a-a125-c98649b2d5ff", + "key": "a340ef18-86d4-4b45-a2dd-8f359fe1bbd7", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4712,29 +5021,39 @@ "wellName": "G1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "a16f16d6-2d46-40c7-a133-4f9abd72cf48", + "key": "520ade31-221c-4cd2-b92a-5b832b8fdb64", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "fb5846b6-0d7b-4747-b27f-fd6f2d2f1575", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "a5e760a7-02e9-40df-abe8-cc77ab928c4b", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "d90d2351-8a74-4912-9e46-5c9635de351d", + "key": "1b062ec1-22be-4c88-b5c4-9d657ae10e4e", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4743,7 +5062,7 @@ }, { "commandType": "aspirate", - "key": "e143a895-a495-4e36-899d-ae2ca6d3bda6", + "key": "ad33c8e0-cea7-4879-9ff1-53106967838a", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4751,14 +5070,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "87c77c51-adb3-49fa-ad44-9288625d4b35", + "key": "e288d570-4ee8-4632-a8ac-0d216bc255b1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4766,29 +5089,39 @@ "wellName": "H1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "6f7d9b7e-9483-4611-8017-a16229d0dfe0", + "key": "bf8e795f-6860-41b6-9e7b-c3224903db97", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "628753d7-3932-4632-a5ec-a41795c9c774", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "9d11926e-9bd6-40f4-9684-876842e33e87", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "bbbfc586-62ca-40c0-8024-1913916a5ac4", + "key": "ca741ecb-2961-429c-8faf-50d25bacdc7c", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4797,7 +5130,7 @@ }, { "commandType": "aspirate", - "key": "b6123803-d123-4c3c-a51c-db80ffe80926", + "key": "7ce820fa-9ac9-4461-8ae6-1dd96c75f1f1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4805,14 +5138,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "dispense", - "key": "e17617fc-2e85-43a5-a67b-15f7eff630ee", + "key": "534ebce3-a564-4a91-bb12-deeea288eee9", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "volume": 50, @@ -4820,29 +5157,39 @@ "wellName": "H1", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 478 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "60b55771-dbf8-460f-88b6-a6511398b61b", + "key": "fc548a47-2f2e-45e2-8b5b-15b3b3ffe1d1", "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "2be58694-e996-4547-84d7-47b63b7b5cb7", - "params": { "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" } + "key": "71167f1f-0c3e-418f-95a9-4dcb31db46a1", + "params": { + "pipetteId": "2e7c6344-58ab-465c-b542-489883cb63fe" + } }, { "commandType": "pickUpTip", - "key": "adc4dc42-ed18-4549-a922-186e5d8c8e91", + "key": "ba8dc1fa-9644-430e-a43c-1a6a09d00e90", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "labwareId": "23ed35de-5bfd-4bb0-8f54-da99a2804ed9:opentrons/opentrons_flex_96_filtertiprack_50ul/1", @@ -4851,7 +5198,7 @@ }, { "commandType": "configureForVolume", - "key": "81502381-d22e-435c-a1c6-a6561abf4c14", + "key": "cd5e9721-5afa-44b4-9368-70e7ef3fdce7", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10 @@ -4859,7 +5206,7 @@ }, { "commandType": "aspirate", - "key": "9d0eef4b-26e2-4b6d-bf83-72b57f00247d", + "key": "43860409-9fe5-48c6-a4fb-a64c0e2012d8", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4867,14 +5214,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 35 } }, { "commandType": "dispense", - "key": "b689a855-ff45-46d6-8f99-96f5b3480122", + "key": "3bd05fd6-c9dd-4613-b450-c716be97d8e8", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4882,14 +5233,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 57 } }, { "commandType": "aspirate", - "key": "a6567fc7-664e-4d28-861f-8620923fc83f", + "key": "7d093d28-264b-49f2-941d-09195dc0cfc3", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4897,14 +5252,18 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 35 } }, { "commandType": "dispense", - "key": "68593075-6c39-485d-8fee-4cea9c3e5eb0", + "key": "67dc0d1b-0836-4583-836b-7ac262702a5f", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "volume": 10, @@ -4912,66 +5271,83 @@ "wellName": "A1", "wellLocation": { "origin": "bottom", - "offset": { "z": 0.5, "x": 0, "y": 0 } + "offset": { + "z": 0.5, + "x": 0, + "y": 0 + } }, "flowRate": 57 } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "4137561c-659a-4d7a-9e8a-c05aa15d4891", + "key": "7d9805de-c25f-49c8-99a0-ee7a1defcf94", "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "a5389c1e-2544-44ae-9b03-a3464899f971", - "params": { "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193" } + "key": "c838b18a-fed3-4477-a982-c0f5fd843809", + "params": { + "pipetteId": "6d1e53c3-2db3-451b-ad60-3fe13781a193" + } }, { "commandType": "moveLabware", - "key": "950063e3-0e7c-4859-a513-45e7a39444ab", + "key": "b73b865e-67a0-47ff-b61a-282de0b12ec0", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", - "newLocation": { "slotName": "B2" } + "newLocation": { + "slotName": "B2" + } } }, { "commandType": "waitForDuration", - "key": "55dd1085-976e-4145-b4fe-2a6797e0d8be", - "params": { "seconds": 60, "message": "" } + "key": "ad450c68-dca0-4f21-86af-1e5b639abe37", + "params": { + "seconds": 60, + "message": "" + } }, { "commandType": "moveLabware", - "key": "5e1ac5e8-1da6-4fb9-a11c-b078d693afa0", + "key": "59ff1562-939a-47c4-9b4d-51b5a20a92cb", "params": { "labwareId": "fcba73e7-b88e-438e-963e-f8b9a5de0983:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "strategy": "usingGripper", - "newLocation": { "slotName": "C3" } + "newLocation": { + "slotName": "C3" + } } }, { "commandType": "heaterShaker/closeLabwareLatch", - "key": "c27f07bc-657a-4aae-942a-50df0a2ad167", + "key": "abed10a2-eb5a-463f-8186-83ebe073339e", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateHeater", - "key": "058c70b9-7a15-4d4b-80f6-f5d8f0437c81", + "key": "5d2073ca-6c0f-4085-afee-80aa253c7233", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/setAndWaitForShakeSpeed", - "key": "182690d7-0c0a-4cb7-9022-85cca4761637", + "key": "75cea8f7-0e62-4220-8aab-35fa47421ca2", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType", "rpm": 500 @@ -4979,41 +5355,50 @@ }, { "commandType": "heaterShaker/deactivateHeater", - "key": "a2e67135-b880-449d-b114-58bd02a3de57", + "key": "8ccb0159-975a-470e-9423-91b4f4064211", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/deactivateShaker", - "key": "727d5986-def0-4c44-b337-1f327f68f908", + "key": "833d585a-b06c-4c7f-9b37-33b0adb5f91b", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "heaterShaker/openLabwareLatch", - "key": "6b2ed1dd-3d71-45b0-84f5-fb7153a6f325", + "key": "c490c812-a61d-4112-a0b3-a9fbf0d2c171", "params": { "moduleId": "c19dffa3-cb34-4702-bcf6-dcea786257d1:heaterShakerModuleType" } }, { "commandType": "moveLabware", - "key": "f2ecdb28-afae-4342-b441-61fe38d9e069", + "key": "ab7a06f2-9f3e-465a-ab10-b0ded19977ed", "params": { "labwareId": "a793a135-06aa-4ed6-a1d3-c176c7810afa:opentrons/opentrons_24_aluminumblock_nest_1.5ml_snapcap/1", "strategy": "manualMoveWithPause", "newLocation": "offDeck" } }, + { + "commandType": "temperatureModule/deactivate", + "key": "90961514-df6e-4884-9eb7-cf8e03e0f6ae", + "params": { + "moduleId": "ef44ad7f-0fd9-46d6-8bc0-c70785644cc8:temperatureModuleType" + } + }, { "commandType": "moveLabware", - "key": "8f88f8b7-69dd-43c2-b3ce-0404a80c13a6", + "key": "8f4c74e3-0777-4dab-badc-9aa8196ce857", "params": { "labwareId": "239ceac8-23ec-4900-810a-70aeef880273:opentrons/nest_96_wellplate_200ul_flat/2", "strategy": "manualMoveWithPause", - "newLocation": { "slotName": "C2" } + "newLocation": { + "slotName": "C2" + } } } ], diff --git a/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json index 8b8d129418f..e532c026004 100644 --- a/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json +++ b/protocol-designer/fixtures/protocol/8/newAdvancedSettingsAndMultiTemp.json @@ -6,16 +6,16 @@ "author": "", "description": "", "created": 1714565695341, - "lastModified": 1731355906825, + "lastModified": 1738865106620, "category": null, "subcategory": null, "tags": [] }, "designerApplication": { "name": "opentrons/protocol-designer", - "version": "8.2.2", + "version": "8.4.0-alpha.1", "data": { - "_internalAppBuildDate": "Mon, 11 Nov 2024 20:10:44 GMT", + "_internalAppBuildDate": "Thu, 06 Feb 2025 16:23:43 GMT", "defaultValues": { "aspirate_mmFromBottom": 1, "dispense_mmFromBottom": 1, @@ -27,7 +27,10 @@ "opentrons/opentrons_flex_96_tiprack_50ul/1" ] }, - "dismissedWarnings": { "form": [], "timeline": [] }, + "dismissedWarnings": { + "form": [], + "timeline": [] + }, "ingredients": {}, "ingredLocations": {}, "savedStepForms": { @@ -175,7 +178,10 @@ ] } }, - "robot": { "model": "OT-3 Standard", "deckId": "ot3_standard" }, + "robot": { + "model": "OT-3 Standard", + "deckId": "ot3_standard" + }, "labwareDefinitionSchemaId": "opentronsLabwareSchemaV2", "labwareDefinitions": { "opentrons/opentrons_flex_96_tiprack_50ul/1": { @@ -193,7 +199,10 @@ ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] ], - "brand": { "brand": "Opentrons", "brandId": [] }, + "brand": { + "brand": "Opentrons", + "brandId": [] + }, "metadata": { "displayName": "Opentrons Flex 96 Tip Rack 50 µL", "displayCategory": "tipRack", @@ -1188,9 +1197,17 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "stackingOffsetWithLabware": { - "opentrons_flex_96_tiprack_adapter": { "x": 0, "y": 0, "z": 121 } + "opentrons_flex_96_tiprack_adapter": { + "x": 0, + "y": 0, + "z": 121 + } } }, "opentrons/opentrons_96_well_aluminum_block/1": { @@ -1208,7 +1225,10 @@ ["A11", "B11", "C11", "D11", "E11", "F11", "G11", "H11"], ["A12", "B12", "C12", "D12", "E12", "F12", "G12", "H12"] ], - "brand": { "brand": "Opentrons", "brandId": [] }, + "brand": { + "brand": "Opentrons", + "brandId": [] + }, "metadata": { "displayName": "Opentrons 96 Well Aluminum Block", "displayCategory": "aluminumBlock", @@ -2088,7 +2108,9 @@ }, "groups": [ { - "metadata": { "wellBottomShape": "v" }, + "metadata": { + "wellBottomShape": "v" + }, "wells": [ "A1", "B1", @@ -2200,11 +2222,23 @@ "version": 1, "schemaVersion": 2, "allowedRoles": ["adapter"], - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "gripperOffsets": { "default": { - "pickUpOffset": { "x": 0, "y": 0, "z": 0 }, - "dropOffset": { "x": 0, "y": 0, "z": 1 } + "pickUpOffset": { + "x": 0, + "y": 0, + "z": 0 + }, + "dropOffset": { + "x": 0, + "y": 0, + "z": 1 + } } } }, @@ -2501,7 +2535,11 @@ "namespace": "opentrons", "version": 1, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 } + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + } }, "opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2": { "ordering": [ @@ -3404,7 +3442,9 @@ }, "groups": [ { - "metadata": { "wellBottomShape": "v" }, + "metadata": { + "wellBottomShape": "v" + }, "wells": [ "A1", "B1", @@ -3515,13 +3555,29 @@ "namespace": "opentrons", "version": 2, "schemaVersion": 2, - "cornerOffsetFromSlot": { "x": 0, "y": 0, "z": 0 }, + "cornerOffsetFromSlot": { + "x": 0, + "y": 0, + "z": 0 + }, "stackingOffsetWithLabware": { - "opentrons_96_pcr_adapter": { "x": 0, "y": 0, "z": 10.2 }, - "opentrons_96_well_aluminum_block": { "x": 0, "y": 0, "z": 12.66 } + "opentrons_96_pcr_adapter": { + "x": 0, + "y": 0, + "z": 10.2 + }, + "opentrons_96_well_aluminum_block": { + "x": 0, + "y": 0, + "z": 12.66 + } }, "stackingOffsetWithModule": { - "thermocyclerModuleV2": { "x": 0, "y": 0, "z": 10.8 } + "thermocyclerModuleV2": { + "x": 0, + "y": 0, + "z": 10.8 + } } } }, @@ -3530,7 +3586,7 @@ "commandSchemaId": "opentronsCommandSchemaV8", "commands": [ { - "key": "8ba6b5e2-1555-4259-bd70-275c02af22f6", + "key": "5d17baa4-7738-4f3f-a33d-d4401cef44e7", "commandType": "loadPipette", "params": { "pipetteName": "p50_single_flex", @@ -3539,25 +3595,29 @@ } }, { - "key": "b786c5b3-97d1-4deb-ab20-1b7ae2a92e96", + "key": "f10a974a-0c78-4f05-98fe-e3fd3c884d21", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", - "location": { "slotName": "D3" }, + "location": { + "slotName": "D3" + }, "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType" } }, { - "key": "d2f656f7-bb89-4430-8443-01c4f5d558c7", + "key": "76b1e352-3b83-403e-be25-499a3e83d60e", "commandType": "loadModule", "params": { "model": "temperatureModuleV2", - "location": { "slotName": "C3" }, + "location": { + "slotName": "C3" + }, "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType" } }, { - "key": "4295d596-2722-4575-97fe-615528c84168", + "key": "e5f7069a-cd6a-42ce-a04f-3077637ed99d", "commandType": "loadLabware", "params": { "displayName": "Opentrons 96 Well Aluminum Block", @@ -3571,7 +3631,7 @@ } }, { - "key": "858ef51a-50ac-49d9-81d8-3ab0b9d195c2", + "key": "2dbe3f08-c5e3-4bfe-8cd7-606c118af8d5", "commandType": "loadLabware", "params": { "displayName": "Opentrons Flex 96 Tip Rack 50 µL", @@ -3579,11 +3639,13 @@ "loadName": "opentrons_flex_96_tiprack_50ul", "namespace": "opentrons", "version": 1, - "location": { "slotName": "C2" } + "location": { + "slotName": "C2" + } } }, { - "key": "461afa60-d04a-40c1-bd25-0dae844c29b9", + "key": "6094e431-6ea0-4169-bde4-cec2d4e954db", "commandType": "loadLabware", "params": { "displayName": "Opentrons 24 Well Aluminum Block with NEST 1.5 mL Screwcap", @@ -3597,7 +3659,7 @@ } }, { - "key": "f0fd22f2-6318-4a78-9fe4-f28b97ea1bc3", + "key": "58587ef2-f327-4fc3-9ff6-1b5514148358", "commandType": "loadLabware", "params": { "displayName": "NEST 96 Well Plate 100 µL PCR Full Skirt", @@ -3612,7 +3674,7 @@ }, { "commandType": "pickUpTip", - "key": "5c52fcb4-a8a9-47b4-8b0f-2a7ef9aea904", + "key": "ebb2df96-af68-4779-ba91-6e79b7a673e9", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "labwareId": "0d39213c-49c2-4170-bf19-4c09e1b72aca:opentrons/opentrons_flex_96_tiprack_50ul/1", @@ -3621,7 +3683,7 @@ }, { "commandType": "configureForVolume", - "key": "dd1b37d6-eb8c-4616-bc8a-e1f17556234a", + "key": "295e19f1-96ba-4537-8edb-44e5b486b71d", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "volume": 10 @@ -3629,7 +3691,7 @@ }, { "commandType": "aspirate", - "key": "c8ba3637-892e-45c1-8b31-0a975060cdff", + "key": "1114406c-64a0-4972-8591-7e4a1ef9bbed", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "volume": 10, @@ -3637,14 +3699,18 @@ "wellName": "C1", "wellLocation": { "origin": "bottom", - "offset": { "z": 29, "x": 2, "y": -2 } + "offset": { + "z": 29, + "x": 2, + "y": -2 + } }, "flowRate": 35 } }, { "commandType": "dispense", - "key": "eb95a3e1-091d-4646-9324-a2594284bf8f", + "key": "3a126db9-3464-429d-8788-3be2d19ec263", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "volume": 10, @@ -3652,40 +3718,55 @@ "wellName": "B3", "wellLocation": { "origin": "bottom", - "offset": { "z": 1, "x": 0, "y": 0 } + "offset": { + "z": 1, + "x": 0, + "y": 0 + } }, "flowRate": 57 } }, { "commandType": "blowout", - "key": "98f2eee6-1ee5-4ba8-acd5-3b3316560957", + "key": "f1d01c07-d2ed-48f4-bb24-4c84a40f9809", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "labwareId": "c0093e5f-3f7d-4cbf-aa17-d88394108501:opentrons/nest_96_wellplate_100ul_pcr_full_skirt/2", "wellName": "C1", "flowRate": 20, - "wellLocation": { "origin": "top", "offset": { "z": -12 } } + "wellLocation": { + "origin": "top", + "offset": { + "z": -12 + } + } } }, { "commandType": "moveToAddressableAreaForDropTip", - "key": "09bd3532-aa71-4795-a9c9-32ad271aa852", + "key": "7e45032c-467e-414e-81af-68c5914bf0bc", "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0", "addressableAreaName": "movableTrashA3", - "offset": { "x": 0, "y": 0, "z": 0 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, "alternateDropLocation": true } }, { "commandType": "dropTipInPlace", - "key": "ec86f079-6e0e-4eda-a0a1-97199bc852fd", - "params": { "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0" } + "key": "3243f686-d76e-4289-b4d4-e4908fd00c09", + "params": { + "pipetteId": "21087f15-4c03-4587-8a2b-1ba0b5a501a0" + } }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "74a68fe2-9e03-4bff-9ba4-0f125a2cea49", + "key": "de1245cf-8836-402a-83b1-b548f1364fb8", "params": { "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", "celsius": 40 @@ -3693,7 +3774,7 @@ }, { "commandType": "temperatureModule/waitForTemperature", - "key": "9c4a7f7c-6ce3-48a8-ad05-06d2e6b29fdf", + "key": "a7ed2077-2b02-4cbb-af42-ea38fcb7e347", "params": { "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType", "celsius": 40 @@ -3701,7 +3782,7 @@ }, { "commandType": "temperatureModule/setTargetTemperature", - "key": "c70e216e-7e4d-4b78-9c4d-e605ed05a5e3", + "key": "8d9c6af2-e195-4f7c-b630-3dcbaa5d25ba", "params": { "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", "celsius": 4 @@ -3709,11 +3790,25 @@ }, { "commandType": "temperatureModule/waitForTemperature", - "key": "6b9cd83e-c6d3-41f0-a31f-6645ada88d6d", + "key": "ea4487b3-97bf-46d9-be71-df031096c061", "params": { "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType", "celsius": 4 } + }, + { + "commandType": "temperatureModule/deactivate", + "key": "385c6783-55de-4c96-878d-7aeb2585b37f", + "params": { + "moduleId": "d6966555-6c0e-45e0-8056-428d7c486401:temperatureModuleType" + } + }, + { + "commandType": "temperatureModule/deactivate", + "key": "6c7a02c0-96e0-4dba-a763-78cd669a43f8", + "params": { + "moduleId": "b9c56153-9026-42d1-8113-949e15254571:temperatureModuleType" + } } ], "commandAnnotationSchemaId": "opentronsCommandAnnotationSchemaV1", diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx index 1daf86148ee..8e86abdb2ed 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepSummary.tsx @@ -267,18 +267,19 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null { setTemperature, targetTemperature, } = currentStep - const isDeactivating = setTemperature === 'false' + const isSettingTemperature = + setTemperature != null && JSON.parse(String(setTemperature ?? false)) const tempModuleDisplayName = getModuleDisplayName(modules[tempModuleId]?.model) ?? unknownModule - stepSummaryContent = isDeactivating ? ( + stepSummaryContent = isSettingTemperature ? ( ) : ( ) diff --git a/protocol-designer/src/steplist/formLevel/errors.ts b/protocol-designer/src/steplist/formLevel/errors.ts index 71dd9c859c8..efead9117ef 100644 --- a/protocol-designer/src/steplist/formLevel/errors.ts +++ b/protocol-designer/src/steplist/formLevel/errors.ts @@ -559,7 +559,7 @@ export const targetTemperatureRequired = ( fields: HydratedFormData ): FormError | null => { const { setTemperature, targetTemperature } = fields - return setTemperature && !targetTemperature + return JSON.parse(String(setTemperature ?? false)) && !targetTemperature ? TARGET_TEMPERATURE_REQUIRED : null }