From e3ce552028b944949e4c7ef926ec0828fca8bbaf Mon Sep 17 00:00:00 2001 From: Ian London Date: Mon, 6 Apr 2020 16:42:04 -0400 Subject: [PATCH] feat(protocol-designer): add PD Pause form migration for 3.0.x -> 4.0.0 (#5373) * add migration 3.0.x -> 4.0.0 to fix pause values (pauseForAmountOfTime -> pauseAction) Closes #5371 --- .../StepEditForm/forms/PauseForm.js | 20 ++++---- protocol-designer/src/constants.js | 1 + protocol-designer/src/form-types.js | 4 +- .../src/load-file/migration/4_0_0.js | 46 +++++++++++++++++++ .../src/load-file/migration/index.js | 2 + .../src/localization/en/form.json | 2 +- .../src/localization/en/tooltip.json | 2 +- .../src/step-forms/test/reducers.test.js | 8 +++- .../src/steplist/fieldLevel/index.js | 2 +- .../src/steplist/formLevel/errors.js | 19 +++----- .../formLevel/getDefaultsForStepType.js | 2 +- .../dependentFieldsUpdatePause.js | 2 +- .../stepFormToArgs/pauseFormToArgs.js | 2 +- .../test/pauseFormToArgs.test.js | 6 +-- .../src/steplist/formLevel/warnings.js | 14 ++++-- .../actions/__tests__/selectStep.test.js | 2 +- .../src/ui/steps/actions/thunks/index.js | 5 +- 17 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 protocol-designer/src/load-file/migration/4_0_0.js diff --git a/protocol-designer/src/components/StepEditForm/forms/PauseForm.js b/protocol-designer/src/components/StepEditForm/forms/PauseForm.js index 22c40fb3ec3..8a9885ca433 100644 --- a/protocol-designer/src/components/StepEditForm/forms/PauseForm.js +++ b/protocol-designer/src/components/StepEditForm/forms/PauseForm.js @@ -37,9 +37,7 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => { const pauseUntilTempTooltip = (
- {i18n.t( - `tooltip.step_fields.pauseForAmountOfTime.disabled.wait_until_temp` - )} + {i18n.t(`tooltip.step_fields.pauseAction.disabled.wait_until_temp`)}
) @@ -62,11 +60,11 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {
=> {
=> { />
val === PAUSE_UNTIL_TIME} >
@@ -130,11 +128,11 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => { className={cx({ [styles.disabled]: !pauseUntilTempEnabled, })} - name="pauseForAmountOfTime" + name="pauseAction" options={[ { name: i18n.t( - 'form.step_edit_form.field.pauseForAmountOfTime.options.untilTemperature' + 'form.step_edit_form.field.pauseAction.options.untilTemperature' ), value: PAUSE_UNTIL_TEMP, }, @@ -143,7 +141,7 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => { />
val === PAUSE_UNTIL_TEMP} >
diff --git a/protocol-designer/src/constants.js b/protocol-designer/src/constants.js index f14b88d2a54..47bd775a812 100644 --- a/protocol-designer/src/constants.js +++ b/protocol-designer/src/constants.js @@ -155,6 +155,7 @@ export const MODULES_WITH_COLLISION_ISSUES = [ TEMPERATURE_MODULE_V1, ] +// Values for pauseAction field export const PAUSE_UNTIL_RESUME: 'untilResume' = 'untilResume' export const PAUSE_UNTIL_TIME: 'untilTime' = 'untilTime' export const PAUSE_UNTIL_TEMP: 'untilTemperature' = 'untilTemperature' diff --git a/protocol-designer/src/form-types.js b/protocol-designer/src/form-types.js index ac6eb9ac4f2..8d558b9d9a1 100644 --- a/protocol-designer/src/form-types.js +++ b/protocol-designer/src/form-types.js @@ -47,7 +47,7 @@ export type StepFieldName = any // | 'mix_mmFromBottom' // | 'mix_touchTip_mmFromBottom' // | 'path' -// | 'pauseForAmountOfTime' +// | 'pauseAction' // | 'pauseHour' // | 'pauseMessage' // | 'pauseMinute' @@ -121,7 +121,7 @@ export type PauseForm = {| stepType: 'pause', id: StepIdType, - pauseForAmountOfTime?: + pauseAction?: | typeof PAUSE_UNTIL_RESUME | typeof PAUSE_UNTIL_TIME | typeof PAUSE_UNTIL_TEMP, diff --git a/protocol-designer/src/load-file/migration/4_0_0.js b/protocol-designer/src/load-file/migration/4_0_0.js new file mode 100644 index 00000000000..25ce65b3b97 --- /dev/null +++ b/protocol-designer/src/load-file/migration/4_0_0.js @@ -0,0 +1,46 @@ +// @flow +import mapValues from 'lodash/mapValues' +import omit from 'lodash/omit' + +// NOTE: unlike other major bump (schema change) migrations, the only change +// from v3 to v4 protocol schema is adding additional commands. +// In designerApplication.data, there's a "minor bump" migration for changes +// in the Pause form. + +export const PD_VERSION = '4.0.0' + +export const migrateSavedStepForms = (savedStepForms: { [string]: any }) => { + // NOTE: intentionally not importing PAUSE_UNTIL_TIME / PAUSE_UNTIL_TEMP from constants.js + // to protect this particular migration fn from breaking if those values are ever changed. + const PAUSE_ACTION_MAP = { + true: 'untilTime', + false: 'untilResume', + } + + // Pause form key name and value enum changed + return mapValues(savedStepForms, stepForm => { + if (stepForm.stepType === 'pause') { + const prevPauseActionValue = stepForm.pauseForAmountOfTime + let res = omit(stepForm, 'pauseForAmountOfTime') + res.pauseAction = PAUSE_ACTION_MAP[prevPauseActionValue] + return res + } + return stepForm + }) +} + +export const migrateFile = (fileData: any): any => { + return { + ...fileData, + designerApplication: { + ...fileData.designerApplication, + version: PD_VERSION, + data: { + ...fileData.designerApplication.data, + savedStepForms: migrateSavedStepForms( + fileData.designerApplication.data.savedStepForms + ), + }, + }, + } +} diff --git a/protocol-designer/src/load-file/migration/index.js b/protocol-designer/src/load-file/migration/index.js index 938321c1576..2a105db3859 100644 --- a/protocol-designer/src/load-file/migration/index.js +++ b/protocol-designer/src/load-file/migration/index.js @@ -5,6 +5,7 @@ import semver from 'semver' import type { PDProtocolFile } from '../../file-types' import { migrateFile as migrateFileOne } from './1_1_0' import { migrateFile as migrateFileThree } from './3_0_0' +import { migrateFile as migrateFileFour } from './4_0_0' export const OLDEST_MIGRATEABLE_VERSION = '1.0.0' @@ -14,6 +15,7 @@ type MigrationsByVersion = { [Version]: (Object) => Object } const allMigrationsByVersion: MigrationsByVersion = { '1.1.0': migrateFileOne, '3.0.0': migrateFileThree, + '4.0.0': migrateFileFour, } // get all versions to migrate newer than the file's applicationVersion diff --git a/protocol-designer/src/localization/en/form.json b/protocol-designer/src/localization/en/form.json index 5583ae06b7f..a00f8ea8770 100644 --- a/protocol-designer/src/localization/en/form.json +++ b/protocol-designer/src/localization/en/form.json @@ -72,7 +72,7 @@ "step_name": { "label": "Step Name" }, "step_notes": { "label": "Step Notes" }, "mix": { "label": "mix" }, - "pauseForAmountOfTime": { + "pauseAction": { "options": { "untilResume": "Pause until told to resume", "untilTime": "Delay for an amount of time", diff --git a/protocol-designer/src/localization/en/tooltip.json b/protocol-designer/src/localization/en/tooltip.json index 54b9caaf7a0..f4fc53ccb20 100644 --- a/protocol-designer/src/localization/en/tooltip.json +++ b/protocol-designer/src/localization/en/tooltip.json @@ -42,7 +42,7 @@ "blowout_checkbox": "Redundant with disposal volume" } }, - "pauseForAmountOfTime": { + "pauseAction": { "disabled": { "wait_until_temp": "There are no temperature or thermocycler modules on the deck" } diff --git a/protocol-designer/src/step-forms/test/reducers.test.js b/protocol-designer/src/step-forms/test/reducers.test.js index 090e0562158..8e3d5e4d693 100644 --- a/protocol-designer/src/step-forms/test/reducers.test.js +++ b/protocol-designer/src/step-forms/test/reducers.test.js @@ -20,7 +20,11 @@ import { } from '../selectors' import { handleFormChange } from '../../steplist/formLevel/handleFormChange' import { moveDeckItem } from '../../labware-ingred/actions' -import { INITIAL_DECK_SETUP_STEP_ID, SPAN7_8_10_11_SLOT } from '../../constants' +import { + INITIAL_DECK_SETUP_STEP_ID, + SPAN7_8_10_11_SLOT, + PAUSE_UNTIL_TEMP, +} from '../../constants' import type { DeckSlot } from '../../types' jest.mock('../../labware-defs/utils') @@ -842,7 +846,7 @@ describe('savedStepForms reducer: initial deck setup step', () => { stepType: 'pause', stepName: 'pause until 4C', stepDetails: 'some details', - pauseForAmountOfTime: 'untilTemperature', + pauseAction: PAUSE_UNTIL_TEMP, pauseHour: null, pauseMinute: null, pauseSecond: null, diff --git a/protocol-designer/src/steplist/fieldLevel/index.js b/protocol-designer/src/steplist/fieldLevel/index.js index 0392fc4bde4..624dfde8af3 100644 --- a/protocol-designer/src/steplist/fieldLevel/index.js +++ b/protocol-designer/src/steplist/fieldLevel/index.js @@ -135,7 +135,7 @@ const stepFieldHelperMap: { [StepFieldName]: StepFieldHelpers } = { maskValue: composeMaskers(maskToInteger, onlyPositiveNumbers), castValue: Number, }, - pauseForAmountOfTime: { getErrors: composeErrors(requiredField) }, + pauseAction: { getErrors: composeErrors(requiredField) }, pauseTemperature: { getErrors: composeErrors( minFieldValue(MIN_TEMP_MODULE_TEMP), diff --git a/protocol-designer/src/steplist/formLevel/errors.js b/protocol-designer/src/steplist/formLevel/errors.js index 2c23d3316c4..299d6521998 100644 --- a/protocol-designer/src/steplist/formLevel/errors.js +++ b/protocol-designer/src/steplist/formLevel/errors.js @@ -54,20 +54,15 @@ const FORM_ERRORS: { [FormErrorKey]: FormError } = { PAUSE_TYPE_REQUIRED: { title: 'Must either pause for amount of time, until told to resume, or until temperature reached', - dependentFields: ['pauseForAmountOfTime'], + dependentFields: ['pauseAction'], }, TIME_PARAM_REQUIRED: { title: 'Must include hours, minutes, or seconds', - dependentFields: [ - 'pauseForAmountOfTime', - 'pauseHour', - 'pauseMinute', - 'pauseSecond', - ], + dependentFields: ['pauseAction', 'pauseHour', 'pauseMinute', 'pauseSecond'], }, PAUSE_TEMP_PARAM_REQUIRED: { title: 'Temperature is required', - dependentFields: ['pauseForAmountOfTime', 'pauseTemperature'], + dependentFields: ['pauseAction', 'pauseTemperature'], }, WELL_RATIO_MOVE_LIQUID: { title: 'Well selection must be 1 to many, many to 1, or N to N', @@ -141,21 +136,21 @@ export const pauseForTimeOrUntilTold = ( fields: HydratedFormData ): ?FormError => { const { - pauseForAmountOfTime, + pauseAction, pauseHour, pauseMinute, pauseSecond, moduleId, pauseTemperature, } = fields - if (pauseForAmountOfTime === PAUSE_UNTIL_TIME) { + if (pauseAction === PAUSE_UNTIL_TIME) { // user selected pause for amount of time const hours = parseFloat(pauseHour) || 0 const minutes = parseFloat(pauseMinute) || 0 const seconds = parseFloat(pauseSecond) || 0 const totalSeconds = hours * 3600 + minutes * 60 + seconds return totalSeconds <= 0 ? FORM_ERRORS.TIME_PARAM_REQUIRED : null - } else if (pauseForAmountOfTime === PAUSE_UNTIL_TEMP) { + } else if (pauseAction === PAUSE_UNTIL_TEMP) { // user selected pause until temperature reached if (moduleId == null) { // missing module field (reached by deleting a module from deck) @@ -166,7 +161,7 @@ export const pauseForTimeOrUntilTold = ( return FORM_ERRORS.PAUSE_TEMP_PARAM_REQUIRED } return null - } else if (pauseForAmountOfTime === PAUSE_UNTIL_RESUME) { + } else if (pauseAction === PAUSE_UNTIL_RESUME) { // user selected pause until resume return null } else { diff --git a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js index 6652ad7f5d0..450397993f1 100644 --- a/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js +++ b/protocol-designer/src/steplist/formLevel/getDefaultsForStepType.js @@ -66,7 +66,7 @@ export function getDefaultsForStepType( } case 'pause': return { - pauseForAmountOfTime: null, + pauseAction: null, pauseHour: null, pauseMinute: null, pauseSecond: null, diff --git a/protocol-designer/src/steplist/formLevel/handleFormChange/dependentFieldsUpdatePause.js b/protocol-designer/src/steplist/formLevel/handleFormChange/dependentFieldsUpdatePause.js index 15549ccbf80..20f3b991b4a 100644 --- a/protocol-designer/src/steplist/formLevel/handleFormChange/dependentFieldsUpdatePause.js +++ b/protocol-designer/src/steplist/formLevel/handleFormChange/dependentFieldsUpdatePause.js @@ -14,7 +14,7 @@ const updatePatchOnPauseTemperatureChange = ( patch: FormPatch, rawForm: FormData ) => { - if (fieldHasChanged(rawForm, patch, 'pauseForAmountOfTime')) { + if (fieldHasChanged(rawForm, patch, 'pauseAction')) { return { ...patch, ...getDefaultFields( diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/pauseFormToArgs.js b/protocol-designer/src/steplist/formLevel/stepFormToArgs/pauseFormToArgs.js index 33f289b0f87..2255b6cd88b 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/pauseFormToArgs.js +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/pauseFormToArgs.js @@ -18,7 +18,7 @@ export const pauseFormToArgs = ( const temperature = parseFloat(formData['pauseTemperature']) const message = formData['pauseMessage'] || '' - switch (formData.pauseForAmountOfTime) { + switch (formData.pauseAction) { case PAUSE_UNTIL_TEMP: return { commandCreatorFnName: 'awaitTemperature', diff --git a/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/pauseFormToArgs.test.js b/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/pauseFormToArgs.test.js index be33f2efc47..6f7b3424c2b 100644 --- a/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/pauseFormToArgs.test.js +++ b/protocol-designer/src/steplist/formLevel/stepFormToArgs/test/pauseFormToArgs.test.js @@ -10,7 +10,7 @@ describe('pauseFormToArgs', () => { const formData = { stepType: 'pause', id: 'test_id', - pauseForAmountOfTime: PAUSE_UNTIL_TEMP, + pauseAction: PAUSE_UNTIL_TEMP, pauseTemperature: '20', pauseMessage: 'pause message', moduleId: 'some_id', @@ -27,7 +27,7 @@ describe('pauseFormToArgs', () => { const formData = { stepType: 'pause', id: 'test_id', - pauseForAmountOfTime: PAUSE_UNTIL_RESUME, + pauseAction: PAUSE_UNTIL_RESUME, description: 'some description', pauseMessage: 'some message', } @@ -50,7 +50,7 @@ describe('pauseFormToArgs', () => { const formData = { stepType: 'pause', id: 'test_id', - pauseForAmountOfTime: PAUSE_UNTIL_TIME, + pauseAction: PAUSE_UNTIL_TIME, description: 'some description', pauseMessage: 'some message', pauseHour: 1, diff --git a/protocol-designer/src/steplist/formLevel/warnings.js b/protocol-designer/src/steplist/formLevel/warnings.js index 9dfb67a623f..978c243c4e5 100644 --- a/protocol-designer/src/steplist/formLevel/warnings.js +++ b/protocol-designer/src/steplist/formLevel/warnings.js @@ -1,7 +1,11 @@ // @flow import * as React from 'react' import { getWellTotalVolume } from '@opentrons/shared-data' -import { MIN_TEMP_MODULE_TEMP, MAX_TEMP_MODULE_TEMP } from '../../constants' +import { + MIN_TEMP_MODULE_TEMP, + MAX_TEMP_MODULE_TEMP, + PAUSE_UNTIL_TEMP, +} from '../../constants' import { KnowledgeBaseLink } from '../../components/KnowledgeBaseLink' import type { FormError } from './errors' /******************* @@ -58,12 +62,12 @@ const FORM_WARNINGS: { [FormWarningType]: FormWarning } = { PAUSE_TEMPERATURE_MIN_EXCEEDED: { type: 'TEMPERATURE_MIN_EXCEEDED', title: 'Specified temperature is below module minimum', - dependentFields: ['pauseForAmountOfTime', 'pauseTemperature'], + dependentFields: ['pauseAction', 'pauseTemperature'], }, PAUSE_TEMPERATURE_MAX_EXCEEDED: { type: 'TEMPERATURE_MAX_EXCEEDED', title: 'Specified temperature is above module maximum', - dependentFields: ['pauseForAmountOfTime', 'pauseTemperature'], + dependentFields: ['pauseAction', 'pauseTemperature'], }, } @@ -130,8 +134,8 @@ export const temperatureRangeExceeded = ( export const pauseTemperatureRangeExceeded = ( fields: HydratedFormData ): ?FormWarning => { - const { pauseForAmountOfTime, pauseTemperature } = fields - const setTemperature = pauseForAmountOfTime === 'untilTemperature' + const { pauseAction, pauseTemperature } = fields + const setTemperature = pauseAction === PAUSE_UNTIL_TEMP if (setTemperature && pauseTemperature < MIN_TEMP_MODULE_TEMP) { return FORM_WARNINGS.PAUSE_TEMPERATURE_MIN_EXCEEDED } else if (setTemperature && pauseTemperature > MAX_TEMP_MODULE_TEMP) { diff --git a/protocol-designer/src/ui/steps/actions/__tests__/selectStep.test.js b/protocol-designer/src/ui/steps/actions/__tests__/selectStep.test.js index 7ec5006fdaf..fd90cb7a24a 100644 --- a/protocol-designer/src/ui/steps/actions/__tests__/selectStep.test.js +++ b/protocol-designer/src/ui/steps/actions/__tests__/selectStep.test.js @@ -223,7 +223,7 @@ describe('selectStep', () => { id: 'existingStepId', stepName: 'Example pause', stepDetails: 'details', - pauseForAmountOfTime: PAUSE_UNTIL_RESUME, + pauseAction: PAUSE_UNTIL_RESUME, } mock_getStepFormData.mockReturnValue(existingStep) const store = mockStore({}) diff --git a/protocol-designer/src/ui/steps/actions/thunks/index.js b/protocol-designer/src/ui/steps/actions/thunks/index.js index ab26581f632..d065da7663a 100644 --- a/protocol-designer/src/ui/steps/actions/thunks/index.js +++ b/protocol-designer/src/ui/steps/actions/thunks/index.js @@ -6,6 +6,7 @@ import { } from '../../../../step-forms/selectors' import { changeFormInput } from '../../../../steplist/actions/actions' +import { PAUSE_UNTIL_TEMP } from '../../../../constants' import { uuid } from '../../../../utils' import { selectors as labwareIngredsSelectors } from '../../../../labware-ingred/selectors' import { getSelectedStepId } from '../../selectors' @@ -173,11 +174,11 @@ export const saveSetTempFormWithAddedPauseUntilTemp = () => ( addStep({ stepType: 'pause' })(dispatch, getState) // NOTE: fields should be set one at a time b/c dependentFieldsUpdate fns can filter out inputs - // contingent on other inputs (eg changing the pauseForAmountOfTime radio button may clear the pauseTemperature). + // contingent on other inputs (eg changing the pauseAction radio button may clear the pauseTemperature). dispatch( changeFormInput({ update: { - pauseForAmountOfTime: 'untilTemperature', + pauseAction: PAUSE_UNTIL_TEMP, }, }) )