From 32b191b4b2fcaee2b30b23a72895da53f17d0c86 Mon Sep 17 00:00:00 2001 From: Katie Adee <kaa328@nyu.edu> Date: Tue, 12 May 2020 10:23:41 -0400 Subject: [PATCH] feat(protocol-designer): Implement presaved step form for TC state (#5641) closes #5596 --- .../test/createPresavedStepForm.test.js | 30 +++ .../utils/createPresavedStepForm.js | 30 +++ .../formLevel/getDefaultsForStepType.js | 1 + ...getNextDefaultTemperatureModuleId.test.js} | 11 +- ...getNextDefaultThermocyclerModuleId.test.js | 176 ++++++++++++++++++ .../getNextDefaultTemperatureModuleId.js | 18 ++ .../getNextDefaultThermocyclerModuleId.js | 17 ++ .../formLevel/getNextDefaultModuleId/index.js | 37 +--- .../src/steplist/formLevel/index.js | 5 +- 9 files changed, 281 insertions(+), 44 deletions(-) rename protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/{getNextDefaultModuleId.test.js => getNextDefaultTemperatureModuleId.test.js} (92%) create mode 100644 protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultThermocyclerModuleId.test.js create mode 100644 protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultTemperatureModuleId.js create mode 100644 protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultThermocyclerModuleId.js diff --git a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.js b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.js index 3e2d69892cf..3d2451a89fe 100644 --- a/protocol-designer/src/step-forms/test/createPresavedStepForm.test.js +++ b/protocol-designer/src/step-forms/test/createPresavedStepForm.test.js @@ -4,6 +4,8 @@ import { MAGNETIC_MODULE_V2, TEMPERATURE_MODULE_TYPE, TEMPERATURE_MODULE_V2, + THERMOCYCLER_MODULE_TYPE, + THERMOCYCLER_MODULE_V1, } from '@opentrons/shared-data' import { fixtureP10Single } from '@opentrons/shared-data/pipette/fixtures/name' import { @@ -56,6 +58,12 @@ beforeEach(() => { model: TEMPERATURE_MODULE_V2, slot: '3', }, + someThermocyclerModuleId: { + id: 'someTemperatureModuleId', + type: THERMOCYCLER_MODULE_TYPE, + model: THERMOCYCLER_MODULE_V1, + slot: '3', + }, }, pipettes: { leftPipetteId: { ...leftPipette, mount: 'left' } }, }, @@ -257,4 +265,26 @@ describe('createPresavedStepForm', () => { stepDetails: '', }) }) + + it('should set a default thermocycler module when a Thermocycler step is added', () => { + const args = { + ...defaultArgs, + stepType: 'thermocycler', + } + + expect(createPresavedStepForm(args)).toEqual({ + id: stepId, + stepType: 'thermocycler', + moduleId: 'someThermocyclerModuleId', + // TC Default field + stepName: 'thermocycler', + stepDetails: '', + thermocyclerFormType: 'thermocyclerState', + blockIsActive: false, + blockTargetTemp: null, + lidIsActive: false, + lidTargetTemp: null, + lidOpen: null, + }) + }) }) diff --git a/protocol-designer/src/step-forms/utils/createPresavedStepForm.js b/protocol-designer/src/step-forms/utils/createPresavedStepForm.js index 12c8ba63c57..e68cba8a723 100644 --- a/protocol-designer/src/step-forms/utils/createPresavedStepForm.js +++ b/protocol-designer/src/step-forms/utils/createPresavedStepForm.js @@ -6,6 +6,7 @@ import { getNextDefaultMagnetAction, getNextDefaultPipetteId, getNextDefaultTemperatureModuleId, + getNextDefaultThermocyclerModuleId, handleFormChange, } from '../../steplist/formLevel' import { @@ -140,6 +141,27 @@ const _patchTemperatureModuleId = (args: {| return null } +const _patchThermocyclerModuleId = (args: {| + initialDeckSetup: InitialDeckSetup, + orderedStepIds: OrderedStepIdsState, + savedStepForms: SavedStepFormState, + stepType: StepType, +|}): FormUpdater => () => { + const { initialDeckSetup, orderedStepIds, savedStepForms, stepType } = args + + const hasThermocyclerModuleId = stepType === 'thermocycler' + + if (hasThermocyclerModuleId) { + const moduleId = getNextDefaultThermocyclerModuleId( + savedStepForms, + orderedStepIds, + initialDeckSetup.modules + ) + return { moduleId } + } + return null +} + export const createPresavedStepForm = ({ initialDeckSetup, labwareEntities, @@ -176,11 +198,19 @@ export const createPresavedStepForm = ({ stepType, }) + const updateThermocyclerModuleId = _patchThermocyclerModuleId({ + initialDeckSetup, + orderedStepIds, + savedStepForms, + stepType, + }) + // finally, compose and apply all the updaters in order, // passing the applied result from one updater as the input of the next return [ updateDefaultPipette, updateTemperatureModuleId, + updateThermocyclerModuleId, updateMagneticModuleId, ].reduce<FormData>( (acc, updater: FormUpdater) => { diff --git a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js index eade086daf6..64d7119a882 100644 --- a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js +++ b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js @@ -100,6 +100,7 @@ export function getDefaultsForStepType( blockIsActive: false, blockTargetTemp: null, lidIsActive: false, + lidTargetTemp: null, lidOpen: null, } default: diff --git a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultModuleId.test.js b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultTemperatureModuleId.test.js similarity index 92% rename from protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultModuleId.test.js rename to protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultTemperatureModuleId.test.js index 27f65e41f93..e666c7625ba 100644 --- a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultModuleId.test.js +++ b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultTemperatureModuleId.test.js @@ -8,7 +8,7 @@ import { THERMOCYCLER_MODULE_V1, } from '@opentrons/shared-data' import { TEMPERATURE_DEACTIVATED } from '../../../../constants' -import { getNextDefaultTemperatureModuleId } from '..' +import { getNextDefaultTemperatureModuleId } from '../getNextDefaultTemperatureModuleId' const getThermocycler = () => ({ id: 'tcId', @@ -54,13 +54,6 @@ describe('getNextDefaultTemperatureModuleId', () => { }, expected: 'tempId', }, - { - testMsg: 'thermocycler only: use tc', - equippedModulesById: { - tcId: getThermocycler(), - }, - expected: 'tcId', - }, { testMsg: 'only mag module present: return null', equippedModulesById: { @@ -85,7 +78,7 @@ describe('getNextDefaultTemperatureModuleId', () => { }) }) }) - // TODO (ka 2019-12-20): Add in tests for existing temperature form steps once wired up + describe('previous forms', () => { const testCases = [ { diff --git a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultThermocyclerModuleId.test.js b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultThermocyclerModuleId.test.js new file mode 100644 index 00000000000..1bf94137184 --- /dev/null +++ b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/__tests__/getNextDefaultThermocyclerModuleId.test.js @@ -0,0 +1,176 @@ +// @flow +import { + MAGNETIC_MODULE_TYPE, + TEMPERATURE_MODULE_TYPE, + THERMOCYCLER_MODULE_TYPE, + MAGNETIC_MODULE_V1, + TEMPERATURE_MODULE_V1, + THERMOCYCLER_MODULE_V1, +} from '@opentrons/shared-data' +import { TEMPERATURE_DEACTIVATED } from '../../../../constants' +import { getNextDefaultThermocyclerModuleId } from '../getNextDefaultThermocyclerModuleId' + +const getThermocycler = () => ({ + id: 'tcId', + type: THERMOCYCLER_MODULE_TYPE, + model: THERMOCYCLER_MODULE_V1, + slot: '_span781011', + moduleState: { + type: THERMOCYCLER_MODULE_TYPE, + blockTargetTemp: null, + lidTargetTemp: null, + lidOpen: null, + }, +}) + +const getMag = () => ({ + id: 'magId', + type: MAGNETIC_MODULE_TYPE, + model: MAGNETIC_MODULE_V1, + slot: '_span781011', + moduleState: { type: MAGNETIC_MODULE_TYPE, engaged: false }, +}) + +const getTemp = () => ({ + id: 'tempId', + type: TEMPERATURE_MODULE_TYPE, + model: TEMPERATURE_MODULE_V1, + slot: '3', + moduleState: { + type: TEMPERATURE_MODULE_TYPE, + status: TEMPERATURE_DEACTIVATED, + targetTemperature: null, + }, +}) + +describe('getNextDefaultThermocyclerModuleId', () => { + describe('NO previous forms', () => { + const testCases = [ + { + testMsg: 'temp and TC module present: use TC', + equippedModulesById: { + tempId: getTemp(), + tcId: getThermocycler(), + }, + expected: 'tcId', + }, + { + testMsg: 'only TC module present: use TC', + equippedModulesById: { + tcId: getThermocycler(), + }, + expected: 'tcId', + }, + + { + testMsg: 'only mag module present: return null', + equippedModulesById: { + magId: getMag(), + }, + expected: null, + }, + ] + + testCases.forEach(({ testMsg, equippedModulesById, expected }) => { + it(testMsg, () => { + const savedForms = {} + const orderedStepIds = [] + + const result = getNextDefaultThermocyclerModuleId( + savedForms, + orderedStepIds, + equippedModulesById + ) + + expect(result).toBe(expected) + }) + }) + }) + + describe('previous forms', () => { + const testCases = [ + { + testMsg: 'temp and tc present, last step was tc: use tc mod', + equippedModulesById: { + tempId: getTemp(), + tcId: getThermocycler(), + }, + savedForms: { + tempStepId: { + id: 'tempStepId', + stepType: 'temperature', + stepName: 'temperature', + moduleId: 'tempId', + }, + tcStepId: { + id: 'tcStepId', + stepType: THERMOCYCLER_MODULE_TYPE, + stepName: THERMOCYCLER_MODULE_TYPE, + moduleId: 'tcId', + }, + }, + orderedStepIds: ['tempStepId', 'tcStepId'], + expected: 'tcId', + }, + { + testMsg: 'temp and mag present return null', + equippedModulesById: { + magId: { + id: 'magId', + type: MAGNETIC_MODULE_TYPE, + model: MAGNETIC_MODULE_V1, + slot: '_span781011', + moduleState: { type: MAGNETIC_MODULE_TYPE, engaged: false }, + }, + tempId: { + id: 'tempId', + type: TEMPERATURE_MODULE_TYPE, + model: TEMPERATURE_MODULE_V1, + slot: '3', + moduleState: { + type: TEMPERATURE_MODULE_TYPE, + status: TEMPERATURE_DEACTIVATED, + targetTemperature: null, + }, + }, + }, + savedForms: { + tempStepId: { + id: 'tempStepId', + stepType: 'temperature', + stepName: 'temperature', + moduleId: 'tempId', + }, + magStepId: { + id: 'magStepId', + stepType: 'magnet', + stepName: 'magnet', + moduleId: 'magdeckId', + }, + }, + orderedStepIds: ['tempStepId', 'magStepId'], + expected: null, + }, + ] + + testCases.forEach( + ({ + testMsg, + savedForms = {}, + equippedModulesById, + orderedStepIds = [], + expected, + }) => { + it(testMsg, () => { + const result = getNextDefaultThermocyclerModuleId( + savedForms, + orderedStepIds, + equippedModulesById + ) + + expect(result).toBe(expected) + }) + } + ) + }) +}) diff --git a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultTemperatureModuleId.js b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultTemperatureModuleId.js new file mode 100644 index 00000000000..8399b2d618b --- /dev/null +++ b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultTemperatureModuleId.js @@ -0,0 +1,18 @@ +// @flow +import findKey from 'lodash/findKey' + +import { TEMPERATURE_MODULE_TYPE } from '@opentrons/shared-data' + +import type { ModuleOnDeck } from '../../../step-forms' +import type { StepIdType, FormData } from '../../../form-types' + +export function getNextDefaultTemperatureModuleId( + savedForms: { [StepIdType]: FormData }, + orderedStepIds: Array<StepIdType>, + equippedModulesById: { [moduleId: string]: ModuleOnDeck } +): string | null { + return ( + findKey(equippedModulesById, m => m.type === TEMPERATURE_MODULE_TYPE) || + null + ) +} diff --git a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultThermocyclerModuleId.js b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultThermocyclerModuleId.js new file mode 100644 index 00000000000..b7c6a51b650 --- /dev/null +++ b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/getNextDefaultThermocyclerModuleId.js @@ -0,0 +1,17 @@ +// @flow +import findKey from 'lodash/findKey' +import { THERMOCYCLER_MODULE_TYPE } from '@opentrons/shared-data' + +import type { ModuleOnDeck } from '../../../step-forms' +import type { StepIdType, FormData } from '../../../form-types' + +export function getNextDefaultThermocyclerModuleId( + savedForms: { [StepIdType]: FormData }, + orderedStepIds: Array<StepIdType>, + equippedModulesById: { [moduleId: string]: ModuleOnDeck } +): string | null { + return ( + findKey(equippedModulesById, m => m.type === THERMOCYCLER_MODULE_TYPE) || + null + ) +} diff --git a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/index.js b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/index.js index 252b599e9c9..8da44aafa30 100644 --- a/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/index.js +++ b/protocol-designer/src/steplist/formLevel/getNextDefaultModuleId/index.js @@ -1,35 +1,4 @@ -// @flow -import findKey from 'lodash/findKey' -import last from 'lodash/last' -import { - TEMPERATURE_MODULE_TYPE, - THERMOCYCLER_MODULE_TYPE, -} from '@opentrons/shared-data' +import { getNextDefaultTemperatureModuleId } from './getNextDefaultTemperatureModuleId' +import { getNextDefaultThermocyclerModuleId } from './getNextDefaultThermocyclerModuleId' -import type { ModuleOnDeck } from '../../../step-forms' -import type { StepIdType, FormData } from '../../../form-types' - -const isLastStepTemp = (lastModuleStep: FormData = {}): boolean => - !!(lastModuleStep.moduleId && lastModuleStep.stepType === 'temperature') - -export function getNextDefaultTemperatureModuleId( - savedForms: { [StepIdType]: FormData }, - orderedStepIds: Array<StepIdType>, - equippedModulesById: { [moduleId: string]: ModuleOnDeck } -): string | null { - const prevModuleSteps = orderedStepIds - .map(stepId => savedForms[stepId]) - .filter(form => form && form.moduleId) - - const lastModuleStep = last(prevModuleSteps) - - // TODO (ka 2019-12-20): Since we are hiding the thermocylcer module as an option for now, - // should we simplify this to only return temperature modules? - const nextDefaultModule: string | null = - (isLastStepTemp(lastModuleStep) && lastModuleStep.moduleId) || - findKey(equippedModulesById, m => m.type === TEMPERATURE_MODULE_TYPE) || - findKey(equippedModulesById, m => m.type === THERMOCYCLER_MODULE_TYPE) || - null - - return nextDefaultModule || null -} +export { getNextDefaultTemperatureModuleId, getNextDefaultThermocyclerModuleId } diff --git a/protocol-designer/src/steplist/formLevel/index.js b/protocol-designer/src/steplist/formLevel/index.js index 7b6a95b4ecd..92e5dfb3054 100644 --- a/protocol-designer/src/steplist/formLevel/index.js +++ b/protocol-designer/src/steplist/formLevel/index.js @@ -30,7 +30,10 @@ export { createBlankForm } from './createBlankForm' export { getDefaultsForStepType } from './getDefaultsForStepType' export { getDisabledFields } from './getDisabledFields' export { getNextDefaultPipetteId } from './getNextDefaultPipetteId' -export { getNextDefaultTemperatureModuleId } from './getNextDefaultModuleId' +export { + getNextDefaultTemperatureModuleId, + getNextDefaultThermocyclerModuleId, +} from './getNextDefaultModuleId' export { getNextDefaultMagnetAction } from './getNextDefaultMagnetAction' export { getNextDefaultEngageHeight } from './getNextDefaultEngageHeight' export { stepFormToArgs } from './stepFormToArgs'