Skip to content

Commit

Permalink
refactor(protocol-designer): unite delete labware and handleFormChang…
Browse files Browse the repository at this point in the history
…e logic (#2680)

There was some unecessary duplication of concerns between handling unsaved form changes and handling
deletion of labware in all saved forms. This addition creates a function that can be used by both
cases, to unite the logic into one source of truth.

Closes #2657
  • Loading branch information
b-cooper authored Nov 15, 2018
1 parent 6f8b2c9 commit 12f020c
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 69 deletions.
63 changes: 32 additions & 31 deletions protocol-designer/src/steplist/actions/handleFormChange.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {selectors as labwareIngredSelectors} from '../../labware-ingred/reducers
import type {PipetteChannels} from '@opentrons/shared-data'
import type {BaseState, GetState} from '../../types'
import type {FormData} from '../../form-types'

import type {StepFieldName} from '../fieldLevel'
import type {ChangeFormPayload} from './types'

function _getAllWells (
Expand Down Expand Up @@ -54,34 +54,54 @@ const getChannels = (pipetteId: string, state: BaseState): PipetteChannels => {
function handleFormChange (payload: ChangeFormPayload, getState: GetState): ChangeFormPayload {
// Use state to handle form changes
const baseState = getState()
const unsavedForm = selectors.formData(baseState)
let updateOverrides = {}
const unsavedForm = selectors.getUnsavedForm(baseState)

// pass thru, unchanged
if (unsavedForm == null) { return payload }

let updateOverrides = getChangeLabwareEffects(payload.update)

if (unsavedForm.pipette && payload.update.pipette) {
if (typeof payload.update.pipette !== 'string') {
// this should not happen!
console.error('no next pipette, could not handleFormChange')
return payload
}
const nextChannels = getChannels(payload.update.pipette, baseState)
updateOverrides = {
...updateOverrides,
...reconcileFormPipette(unsavedForm, baseState, payload.update.pipette, nextChannels),
}
}

if (unsavedForm == null) {
// pass thru, unchanged
return payload
return {
update: {
...payload.update,
...updateOverrides,
},
}
}

export const getChangeLabwareEffects = (updateFormData: {[StepFieldName]: ?mixed}) => {
let updateOverrides = {}
// Changing labware clears wells selection: source labware
if ('aspirate_labware' in payload.update) {
if ('aspirate_labware' in updateFormData) {
updateOverrides = {
...updateOverrides,
'aspirate_wells': null,
'aspirate_mmFromBottom': DEFAULT_MM_FROM_BOTTOM_ASPIRATE,
}
}

// Changing labware clears wells selection: dest labware
if ('dispense_labware' in payload.update) {
if ('dispense_labware' in updateFormData) {
updateOverrides = {
...updateOverrides,
'dispense_wells': null,
'dispense_mmFromBottom': DEFAULT_MM_FROM_BOTTOM_DISPENSE,
}
}

// Changing labware clears wells selection: labware (eg, mix)
if ('labware' in payload.update) {
if ('labware' in updateFormData) {
updateOverrides = {
...updateOverrides,
'wells': null,
Expand All @@ -90,26 +110,7 @@ function handleFormChange (payload: ChangeFormPayload, getState: GetState): Chan
'dispense_mmFromBottom': DEFAULT_MM_FROM_BOTTOM_DISPENSE,
}
}

if (unsavedForm.pipette && payload.update.pipette) {
if (typeof payload.update.pipette !== 'string') {
// this should not happen!
console.error('no next pipette, could not handleFormChange')
return payload
}
const nextChannels = getChannels(payload.update.pipette, baseState)
updateOverrides = {
...updateOverrides,
...reconcileFormPipette(unsavedForm, baseState, payload.update.pipette, nextChannels),
}
}

return {
update: {
...payload.update,
...updateOverrides,
},
}
return updateOverrides
}

export const reconcileFormPipette = (formData: FormData, baseState: BaseState, nextPipetteId: ?mixed, nextChannels: ?number) => {
Expand Down
5 changes: 3 additions & 2 deletions protocol-designer/src/steplist/actions/types.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// @flow
import type {StepFieldName} from '../fieldLevel'

// Update Form input (onChange on inputs)
export type ChangeFormPayload = {
// TODO Ian 2018-05-04 use StepType + FormData type to properly type this payload.
// Accessor strings and values depend on StepType
stepType?: string,
update: {
[accessor: string]: ?mixed, // string | boolean | Array<string> | null,
[StepFieldName]: ?mixed, // string | boolean | Array<string> | null,
},
}

export type ChangeSavedFormPayload = {
stepId?: string,
update: {
[accessor: string]: ?mixed, // string | boolean | Array<string> | null,
[StepFieldName]: ?mixed, // string | boolean | Array<string> | null,
},
}
54 changes: 18 additions & 36 deletions protocol-designer/src/steplist/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {handleActions} from 'redux-actions'
import type {ActionType, Reducer} from 'redux-actions'
import omit from 'lodash/omit'
import mapValues from 'lodash/mapValues'
import reduce from 'lodash/reduce'

import {getPDMetadata} from '../file-types'

Expand Down Expand Up @@ -45,6 +46,7 @@ import {
toggleStepCollapsed,
type ChangeSavedStepFormAction,
} from './actions'
import {getChangeLabwareEffects} from './actions/handleFormChange'

type FormState = FormData | null

Expand Down Expand Up @@ -131,13 +133,6 @@ type SavedStepFormState = {
[StepIdType]: FormData,
}

const LABWARE_FIELD_NAMES = [
'aspirate_labware',
'dispense_blowout_labware',
'dispense_labware',
'labware',
]

const savedStepForms: Reducer<SavedStepFormState, *> = handleActions({
SAVE_STEP_FORM: (state, action: SaveStepFormAction) => ({
...state,
Expand All @@ -151,39 +146,26 @@ const savedStepForms: Reducer<SavedStepFormState, *> = handleActions({
...stepForm,
}))
},
DELETE_CONTAINER: (state: SavedStepFormState, action: DeleteContainerAction): SavedStepFormState => {
const {payload} = action
return mapValues(state, savedForm => {
let dependentFields = []
const withoutDeletedLabware = mapValues(savedForm, (value, fieldName) => {
const isLabware = LABWARE_FIELD_NAMES.includes(fieldName)
if (isLabware && value === payload.containerId) {
switch (fieldName) {
case 'aspirate_labware': {
dependentFields = [...dependentFields, 'aspirate_wells']
break
}
case 'dispense_labware': {
dependentFields = [...dependentFields, 'dispense_wells']
break
}
case 'labware': {
dependentFields = [...dependentFields, 'wells']
break
}
DELETE_CONTAINER: (state: SavedStepFormState, action: DeleteContainerAction): SavedStepFormState => (
mapValues(state, savedForm => {
const deleteLabwareUpdate = reduce(savedForm, (acc, value, fieldName) => {
if (value === action.payload.containerId) {
const formLabwareFieldUpdate = {[fieldName]: null}
return {
...acc,
...formLabwareFieldUpdate,
...getChangeLabwareEffects(formLabwareFieldUpdate),
}
return null
} else {
return value
return acc
}
})
const withoutDependentFields = mapValues(withoutDeletedLabware, (value, fieldName) => {
if (dependentFields.includes(fieldName)) return null
return value
})
return withoutDependentFields
}, {})
return {
...savedForm,
...deleteLabwareUpdate,
}
})
},
),
CHANGE_SAVED_STEP_FORM: (state: SavedStepFormState, action: ChangeSavedStepFormAction): SavedStepFormState => ({
...state,
[action.payload.stepId]: {
Expand Down

0 comments on commit 12f020c

Please sign in to comment.