Skip to content

Commit 466bd00

Browse files
authored
feat(protocol-designer): add modal fields (#7440)
Closes #7239 Co-authored-by: @Kadee80 and @shlokamin
1 parent 3873f17 commit 466bd00

File tree

11 files changed

+170
-77
lines changed

11 files changed

+170
-77
lines changed

protocol-designer/src/components/BatchEditForm/index.js

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
BlowoutLocationField,
1313
CheckboxRowField,
1414
DelayFields,
15-
TipPositionField,
15+
FlowRateField,
1616
TextField,
17+
TipPositionField,
18+
WellOrderField,
1719
} from '../StepEditForm/fields'
1820
import { MixFields } from '../StepEditForm/fields/MixFields'
1921
import {
@@ -34,6 +36,7 @@ import {
3436
saveStepFormsMulti,
3537
} from '../../step-forms/actions'
3638
import type { FieldPropsByName } from '../StepEditForm/types'
39+
import type { WellOrderOption } from '../../form-types'
3740
// TODO(IL, 2021-03-01): refactor these fragmented style rules (see #7402)
3841
import formStyles from '../forms/forms.css'
3942
import styles from '../StepEditForm/StepEditForm.css'
@@ -48,19 +51,64 @@ const SourceDestBatchEditMoveLiquidFields = (props: {|
4851
const { prefix, propsForFields } = props
4952
const addFieldNamePrefix = name => `${prefix}_${name}`
5053

51-
const getLabwareIdForField = (name: string): string | null => {
54+
const getLabwareIdForPositioningField = (name: string): string | null => {
5255
const labwareField = getLabwareFieldForPositioningField(name)
5356
const labwareId = propsForFields[labwareField]?.value
5457
return labwareId ? String(labwareId) : null
5558
}
5659

60+
const getPipetteIdForForm = (): string | null => {
61+
const pipetteId = propsForFields.pipette?.value
62+
return pipetteId ? String(pipetteId) : null
63+
}
64+
65+
const getWellOrderFieldValue = (name: string): ?WellOrderOption => {
66+
const val = propsForFields[name]?.value
67+
if (val === 'l2r' || val === 'r2l' || val === 't2b' || val === 'b2t') {
68+
return val
69+
} else {
70+
return null
71+
}
72+
}
73+
5774
return (
5875
<Box className={styles.section_column}>
5976
<Box className={styles.section_header}>
6077
<span className={styles.section_header_text}>
6178
{i18n.t('form.batch_edit_form.settings_for', { prefix })}
6279
</span>
6380
</Box>
81+
82+
<Box className={styles.form_row}>
83+
<FlowRateField
84+
{...propsForFields[addFieldNamePrefix('flowRate')]}
85+
pipetteId={getPipetteIdForForm()}
86+
flowRateType={prefix}
87+
/>
88+
<TipPositionField
89+
{...propsForFields[addFieldNamePrefix('mmFromBottom')]}
90+
labwareId={getLabwareIdForPositioningField(
91+
addFieldNamePrefix('mmFromBottom')
92+
)}
93+
/>
94+
<WellOrderField
95+
prefix={prefix}
96+
label={i18n.t('form.step_edit_form.field.well_order.label')}
97+
firstValue={getWellOrderFieldValue(
98+
addFieldNamePrefix('wellOrder_first')
99+
)}
100+
secondValue={getWellOrderFieldValue(
101+
addFieldNamePrefix('wellOrder_second')
102+
)}
103+
updateFirstWellOrder={
104+
propsForFields[addFieldNamePrefix('wellOrder_first')].updateValue
105+
}
106+
updateSecondWellOrder={
107+
propsForFields[addFieldNamePrefix('wellOrder_second')].updateValue
108+
}
109+
/>
110+
</Box>
111+
64112
{prefix === 'aspirate' && (
65113
<CheckboxRowField
66114
{...propsForFields['preWetTip']}
@@ -78,7 +126,7 @@ const SourceDestBatchEditMoveLiquidFields = (props: {|
78126
checkboxFieldName={addFieldNamePrefix('delay_checkbox')}
79127
secondsFieldName={addFieldNamePrefix('delay_seconds')}
80128
tipPositionFieldName={addFieldNamePrefix('delay_mmFromBottom')}
81-
labwareId={getLabwareIdForField(
129+
labwareId={getLabwareIdForPositioningField(
82130
addFieldNamePrefix('delay_mmFromBottom')
83131
)}
84132
propsForFields={propsForFields}
@@ -90,7 +138,7 @@ const SourceDestBatchEditMoveLiquidFields = (props: {|
90138
>
91139
<TipPositionField
92140
{...propsForFields[addFieldNamePrefix('touchTip_mmFromBottom')]}
93-
labwareId={getLabwareIdForField(
141+
labwareId={getLabwareIdForPositioningField(
94142
addFieldNamePrefix('touchTip_mmFromBottom')
95143
)}
96144
/>

protocol-designer/src/components/StepEditForm/fields/FlowRateField/index.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ import { FlowRateInput, type FlowRateInputProps } from './FlowRateInput'
44
import { connect } from 'react-redux'
55
import { selectors as stepFormSelectors } from '../../../../step-forms'
66
import type { FieldProps } from '../../types'
7-
import type { FormData } from '../../../../form-types'
8-
import type { StepFieldName } from '../../../../steplist/fieldLevel'
97
import type { BaseState } from '../../../../types'
108

119
type OP = {|
1210
...FieldProps,
13-
pipetteFieldName: StepFieldName,
14-
formData: FormData,
11+
pipetteId: ?string,
1512
className?: $PropertyType<FlowRateInputProps, 'className'>,
1613
flowRateType: $PropertyType<FlowRateInputProps, 'flowRateType'>,
1714
label?: $PropertyType<FlowRateInputProps, 'label'>,
@@ -37,9 +34,8 @@ function FlowRateInputWithKey(props: Props) {
3734
}
3835

3936
function mapStateToProps(state: BaseState, ownProps: OP): SP {
40-
const { flowRateType, pipetteFieldName, name, formData } = ownProps
37+
const { flowRateType, pipetteId, name } = ownProps
4138

42-
const pipetteId = formData ? formData[pipetteFieldName] : null
4339
const pipette =
4440
pipetteId != null
4541
? stepFormSelectors.getPipetteEntities(state)[pipetteId]
@@ -69,7 +65,7 @@ function mapStateToProps(state: BaseState, ownProps: OP): SP {
6965
}
7066

7167
const mergeProps = (stateProps: SP, dispatchProps, ownProps: OP): Props => {
72-
const { formData, pipetteFieldName, ...passThruProps } = ownProps
68+
const { pipetteId, ...passThruProps } = ownProps
7369
return { ...stateProps, ...passThruProps }
7470
}
7571

protocol-designer/src/components/StepEditForm/fields/WellOrderField/WellOrderModal.js

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
DropdownField,
1212
} from '@opentrons/components'
1313
import modalStyles from '../../../modals/modal.css'
14-
import type { WellOrderOption, FormData } from '../../../../form-types'
14+
import type { WellOrderOption } from '../../../../form-types'
1515

1616
import { WellOrderViz } from './WellOrderViz'
1717
import styles from './WellOrderInput.css'
@@ -29,17 +29,18 @@ type Props = {|
2929
isOpen: boolean,
3030
closeModal: () => mixed,
3131
prefix: 'aspirate' | 'dispense' | 'mix',
32-
formData: FormData,
32+
firstValue: ?WellOrderOption,
33+
secondValue: ?WellOrderOption,
3334
updateValues: (
3435
firstValue: ?WellOrderOption,
3536
secondValue: ?WellOrderOption
3637
) => void,
3738
|}
3839

39-
type State = {
40-
firstValue: ?WellOrderOption,
41-
secondValue: ?WellOrderOption,
42-
}
40+
type State = {|
41+
firstValue: WellOrderOption,
42+
secondValue: WellOrderOption,
43+
|}
4344

4445
export class WellOrderModal extends React.Component<Props, State> {
4546
constructor(props: Props) {
@@ -55,25 +56,34 @@ export class WellOrderModal extends React.Component<Props, State> {
5556
}
5657

5758
getInitialFirstValues: () => {|
58-
initialFirstValue: ?WellOrderOption,
59-
initialSecondValue: ?WellOrderOption,
59+
initialFirstValue: WellOrderOption,
60+
initialSecondValue: WellOrderOption,
6061
|} = () => {
61-
const { formData, prefix } = this.props
62+
const { firstValue, secondValue } = this.props
63+
if (firstValue == null || secondValue == null) {
64+
return {
65+
initialFirstValue: DEFAULT_FIRST,
66+
initialSecondValue: DEFAULT_SECOND,
67+
}
68+
}
6269
return {
63-
initialFirstValue: formData && formData[`${prefix}_wellOrder_first`],
64-
initialSecondValue: formData && formData[`${prefix}_wellOrder_second`],
70+
initialFirstValue: firstValue,
71+
initialSecondValue: secondValue,
6572
}
6673
}
74+
6775
applyChanges: () => void = () => {
6876
this.props.updateValues(this.state.firstValue, this.state.secondValue)
6977
}
78+
7079
handleReset: () => void = () => {
7180
this.setState(
7281
{ firstValue: DEFAULT_FIRST, secondValue: DEFAULT_SECOND },
7382
this.applyChanges
7483
)
7584
this.props.closeModal()
7685
}
86+
7787
handleCancel: () => void = () => {
7888
const {
7989
initialFirstValue,
@@ -85,10 +95,12 @@ export class WellOrderModal extends React.Component<Props, State> {
8595
)
8696
this.props.closeModal()
8797
}
98+
8899
handleDone: () => void = () => {
89100
this.applyChanges()
90101
this.props.closeModal()
91102
}
103+
92104
makeOnChange: (
93105
ordinality: 'first' | 'second'
94106
) => (
@@ -174,11 +186,7 @@ export class WellOrderModal extends React.Component<Props, State> {
174186
</div>
175187
</FormGroup>
176188
<FormGroup label={i18n.t('modal.well_order.viz_label')}>
177-
<WellOrderViz
178-
prefix={this.props.prefix}
179-
firstValue={firstValue}
180-
secondValue={secondValue}
181-
/>
189+
<WellOrderViz firstValue={firstValue} secondValue={secondValue} />
182190
</FormGroup>
183191
</div>
184192
<div className={modalStyles.button_row_divided}>

protocol-designer/src/components/StepEditForm/fields/WellOrderField/WellOrderViz.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@ import type { WellOrderOption } from '../../../../form-types'
99

1010
import styles from './WellOrderInput.css'
1111

12-
type Props = {
13-
prefix: 'aspirate' | 'dispense' | 'mix',
14-
firstValue: ?WellOrderOption,
15-
secondValue: ?WellOrderOption,
16-
}
12+
type Props = {|
13+
firstValue: WellOrderOption,
14+
secondValue: WellOrderOption,
15+
|}
16+
17+
export const WellOrderViz = (props: Props): React.Node => {
18+
const { firstValue, secondValue } = props
1719

18-
export const WellOrderViz = (props: Props): React.Node => (
19-
<div className={styles.viz_wrapper}>
20-
<img src={WELLS_IMAGE} className={styles.wells_image} />
21-
<img
22-
src={PATH_IMAGE}
23-
className={cx(
24-
styles.path_image,
25-
styles[`${props.firstValue || ''}_first`],
26-
styles[`${props.secondValue || ''}_second`]
27-
)}
28-
/>
29-
</div>
30-
)
20+
return (
21+
<div className={styles.viz_wrapper}>
22+
<img src={WELLS_IMAGE} className={styles.wells_image} />
23+
<img
24+
src={PATH_IMAGE}
25+
className={cx(
26+
styles.path_image,
27+
styles[`${firstValue || ''}_first`],
28+
styles[`${secondValue || ''}_second`]
29+
)}
30+
/>
31+
</div>
32+
)
33+
}

protocol-designer/src/components/StepEditForm/fields/WellOrderField/index.js

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
11
// @flow
22
import * as React from 'react'
3-
import { FormGroup, Tooltip, useHoverTooltip } from '@opentrons/components'
3+
import {
4+
FormGroup,
5+
Text,
6+
Tooltip,
7+
useHoverTooltip,
8+
FONT_WEIGHT_SEMIBOLD,
9+
FONT_SIZE_BODY_1,
10+
} from '@opentrons/components'
411
import cx from 'classnames'
512
import { i18n } from '../../../../localization'
613
import ZIG_ZAG_IMAGE from '../../../../images/zig_zag_icon.svg'
714
import { WellOrderModal } from './WellOrderModal'
815
import stepEditStyles from '../../StepEditForm.css'
916
import styles from './WellOrderInput.css'
10-
import type { FormData } from '../../../../form-types'
1117
import type { FieldProps } from '../../types'
18+
import type { WellOrderOption } from '../../../../form-types'
1219

1320
type Props = {|
1421
className?: ?string,
1522
label?: string,
1623
prefix: 'aspirate' | 'dispense' | 'mix',
17-
formData: FormData,
24+
firstValue: ?WellOrderOption,
25+
secondValue: ?WellOrderOption,
1826
updateFirstWellOrder: $PropertyType<FieldProps, 'updateValue'>,
1927
updateSecondWellOrder: $PropertyType<FieldProps, 'updateValue'>,
2028
|}
2129

2230
export const WellOrderField = (props: Props): React.Node => {
23-
const { formData, updateFirstWellOrder, updateSecondWellOrder } = props
31+
const {
32+
firstValue,
33+
secondValue,
34+
updateFirstWellOrder,
35+
updateSecondWellOrder,
36+
} = props
2437
const [isModalOpen, setModalOpen] = React.useState(false)
2538

2639
const handleOpen = () => {
@@ -36,11 +49,12 @@ export const WellOrderField = (props: Props): React.Node => {
3649
}
3750

3851
const getIconClassNames = () => {
39-
let iconClassNames = []
40-
if (formData) {
41-
const first = formData[`${props.prefix}_wellOrder_first`]
42-
const second = formData[`${props.prefix}_wellOrder_second`]
43-
iconClassNames = [styles[`${first}_first`], styles[`${second}_second`]]
52+
const iconClassNames = []
53+
if (firstValue) {
54+
iconClassNames.push(styles[`${firstValue}_first`])
55+
}
56+
if (secondValue) {
57+
iconClassNames.push(styles[`${secondValue}_second`])
4458
}
4559
return iconClassNames
4660
}
@@ -63,18 +77,31 @@ export const WellOrderField = (props: Props): React.Node => {
6377
prefix={props.prefix}
6478
closeModal={handleClose}
6579
isOpen={isModalOpen}
66-
formData={formData}
6780
updateValues={updateValues}
81+
firstValue={firstValue}
82+
secondValue={secondValue}
6883
/>
69-
<img
70-
onClick={handleOpen}
71-
src={ZIG_ZAG_IMAGE}
72-
className={cx(
73-
styles.well_order_icon,
74-
{ [styles.icon_with_label]: props.label },
75-
getIconClassNames()
76-
)}
77-
/>
84+
{firstValue != null && secondValue != null ? (
85+
<img
86+
onClick={handleOpen}
87+
src={ZIG_ZAG_IMAGE}
88+
className={cx(
89+
styles.well_order_icon,
90+
{ [styles.icon_with_label]: props.label },
91+
getIconClassNames()
92+
)}
93+
/>
94+
) : (
95+
<Text
96+
onClick={handleOpen}
97+
fontWeight={FONT_WEIGHT_SEMIBOLD}
98+
fontSize={FONT_SIZE_BODY_1}
99+
paddingTop="0.5rem"
100+
paddingBottom="0.325rem"
101+
>
102+
{i18n.t('form.step_edit_form.field.well_order.mixed')}
103+
</Text>
104+
)}
78105
</FormGroup>
79106
</div>
80107
</>

protocol-designer/src/components/StepEditForm/fields/__tests__/WellOrderField.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ describe('WellOrderField', () => {
1212
beforeEach(() => {
1313
props = {
1414
prefix: 'aspirate',
15-
formData: ({}: any),
15+
firstValue: null,
16+
secondValue: null,
1617
updateFirstWellOrder: jest.fn(),
1718
updateSecondWellOrder: jest.fn(),
1819
}

0 commit comments

Comments
 (0)