Skip to content

Commit

Permalink
feat(protocol-designer): add PD Pause form migration for 3.0.x -> 4.0…
Browse files Browse the repository at this point in the history
….0 (#5373)

* add migration 3.0.x -> 4.0.0 to fix pause values (pauseForAmountOfTime -> pauseAction)

Closes #5371
  • Loading branch information
IanLondon authored Apr 6, 2020
1 parent a6f6594 commit e3ce552
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 44 deletions.
20 changes: 9 additions & 11 deletions protocol-designer/src/components/StepEditForm/forms/PauseForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {

const pauseUntilTempTooltip = (
<div>
{i18n.t(
`tooltip.step_fields.pauseForAmountOfTime.disabled.wait_until_temp`
)}
{i18n.t(`tooltip.step_fields.pauseAction.disabled.wait_until_temp`)}
</div>
)

Expand All @@ -62,11 +60,11 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {
<div className={styles.section_column}>
<div className={styles.checkbox_row}>
<RadioGroupField
name="pauseForAmountOfTime"
name="pauseAction"
options={[
{
name: i18n.t(
'form.step_edit_form.field.pauseForAmountOfTime.options.untilResume'
'form.step_edit_form.field.pauseAction.options.untilResume'
),
value: PAUSE_UNTIL_RESUME,
},
Expand All @@ -76,11 +74,11 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {
</div>
<div className={styles.checkbox_row}>
<RadioGroupField
name="pauseForAmountOfTime"
name="pauseAction"
options={[
{
name: i18n.t(
'form.step_edit_form.field.pauseForAmountOfTime.options.untilTime'
'form.step_edit_form.field.pauseAction.options.untilTime'
),
value: PAUSE_UNTIL_TIME,
},
Expand All @@ -89,7 +87,7 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {
/>
</div>
<ConditionalOnField
name={'pauseForAmountOfTime'}
name={'pauseAction'}
condition={val => val === PAUSE_UNTIL_TIME}
>
<div className={styles.form_row}>
Expand Down Expand Up @@ -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,
},
Expand All @@ -143,7 +141,7 @@ export const PauseForm = (props: PauseFormProps): React.Element<'div'> => {
/>
</div>
<ConditionalOnField
name={'pauseForAmountOfTime'}
name={'pauseAction'}
condition={val => val === PAUSE_UNTIL_TEMP}
>
<div className={styles.form_row}>
Expand Down
1 change: 1 addition & 0 deletions protocol-designer/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions protocol-designer/src/form-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export type StepFieldName = any
// | 'mix_mmFromBottom'
// | 'mix_touchTip_mmFromBottom'
// | 'path'
// | 'pauseForAmountOfTime'
// | 'pauseAction'
// | 'pauseHour'
// | 'pauseMessage'
// | 'pauseMinute'
Expand Down Expand Up @@ -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,
Expand Down
46 changes: 46 additions & 0 deletions protocol-designer/src/load-file/migration/4_0_0.js
Original file line number Diff line number Diff line change
@@ -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
),
},
},
}
}
2 changes: 2 additions & 0 deletions protocol-designer/src/load-file/migration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion protocol-designer/src/localization/en/form.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion protocol-designer/src/localization/en/tooltip.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
8 changes: 6 additions & 2 deletions protocol-designer/src/step-forms/test/reducers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion protocol-designer/src/steplist/fieldLevel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
19 changes: 7 additions & 12 deletions protocol-designer/src/steplist/formLevel/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function getDefaultsForStepType(
}
case 'pause':
return {
pauseForAmountOfTime: null,
pauseAction: null,
pauseHour: null,
pauseMinute: null,
pauseSecond: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const updatePatchOnPauseTemperatureChange = (
patch: FormPatch,
rawForm: FormData
) => {
if (fieldHasChanged(rawForm, patch, 'pauseForAmountOfTime')) {
if (fieldHasChanged(rawForm, patch, 'pauseAction')) {
return {
...patch,
...getDefaultFields(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
}
Expand All @@ -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,
Expand Down
14 changes: 9 additions & 5 deletions protocol-designer/src/steplist/formLevel/warnings.js
Original file line number Diff line number Diff line change
@@ -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'
/*******************
Expand Down Expand Up @@ -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'],
},
}

Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({})
Expand Down
5 changes: 3 additions & 2 deletions protocol-designer/src/ui/steps/actions/thunks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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,
},
})
)
Expand Down

0 comments on commit e3ce552

Please sign in to comment.