diff --git a/protocol-designer/docs/STEP_FORMS_AND_PROTOCOL_TIMELINE.md b/protocol-designer/docs/STEP_FORMS_AND_PROTOCOL_TIMELINE.md index 40bf9f0fc34..6be7733ae4e 100644 --- a/protocol-designer/docs/STEP_FORMS_AND_PROTOCOL_TIMELINE.md +++ b/protocol-designer/docs/STEP_FORMS_AND_PROTOCOL_TIMELINE.md @@ -68,7 +68,7 @@ The rest of this doc will describe the PD-specific side of things: how Step Form **Masking values**: Masking is a behavior where a field rejects updates when they fail to meet a certain condition -- for example, a field only intended for integers will reject changes to add a decimal point. Maskers are used in the presentational layer (specifically, in the `FieldConnector` component) where they should be applied to all updates. -**Field-level errors**: `steplist/fieldLevel` allows you to specify a `getErrors` function for each field. A field can have multiple "error checker" functions that can be composed together; the final result is an array of strings where each represents an error in the field. (NOTE: if there are multiple field-level errors, `FieldConnector` will just join them with `', '`.) +**Field-level errors**: `steplist/fieldLevel` allows you to specify a `getErrors` function for each field. A field can have multiple "error checker" functions that can be composed together; the final result is an array of strings where each represents an error in the field. ~~(NOTE: if there are multiple field-level errors, `FieldConnector` will just join them with `', '`.)~~ **Form-level errors & warnings**: When an error is related to the value of more than one field, it should be specified in `steplist/formLevel` under `getErrors` for that form's `stepType`. Also, there's no such thing as field-level warnings in PD; if need a warning in a form, go to `formLevel` and specify a `getWarnings` function. Form-level errors have a `dependentFields` array associated with them, which is used to ensure that all fields have been touched (are not pristine) before showing the error. diff --git a/protocol-designer/src/components/StepEditForm/fields/FieldConnector.js b/protocol-designer/src/components/StepEditForm/fields/FieldConnector.js deleted file mode 100644 index 133dd708d07..00000000000 --- a/protocol-designer/src/components/StepEditForm/fields/FieldConnector.js +++ /dev/null @@ -1,111 +0,0 @@ -// @flow -import * as React from 'react' -import { connect } from 'react-redux' -import { HoverTooltip, type HoverTooltipHandlers } from '@opentrons/components' -import { actions } from '../../../steplist' -import { selectors as stepFormSelectors } from '../../../step-forms' -import { getFieldErrors, maskField } from '../../../steplist/fieldLevel' -import { getDisabledFields } from '../../../steplist/formLevel' -import type { BaseState, ThunkDispatch } from '../../../types' -import type { StepFieldName } from '../../../form-types' -import { getTooltipForField } from '../utils' - -type FieldRenderProps = { - value: ?mixed, - updateValue: (?mixed) => void, - errorToShow: ?string, - hoverTooltipHandlers?: ?HoverTooltipHandlers, - disabled: boolean, -} - -type OP = { - name: StepFieldName, - render: FieldRenderProps => React.Node, // TODO: type StepField - dirtyFields?: Array, - focusedField?: StepFieldName, - tooltipComponent?: React.Node, -} - -type SP = {| value?: ?mixed, stepType: ?string, disabled: boolean |} - -type DP = {| updateValue: (?mixed) => void |} - -type StepFieldProps = { ...$Exact, ...SP, ...DP } - -const FieldConnectorComponent = (props: StepFieldProps) => { - const { - name, - render, - stepType, - value, - updateValue, - focusedField, - dirtyFields, - disabled, - } = props - const showErrors = showFieldErrors({ name, focusedField, dirtyFields }) - const errors = getFieldErrors(name, value) - const errorToShow = showErrors && errors.length > 0 ? errors.join(', ') : null - - const tooltipComponent = - props.tooltipComponent || getTooltipForField(stepType, name, disabled) - - if (!tooltipComponent) - return render({ value, updateValue, errorToShow, disabled }) - - return ( - - {hoverTooltipHandlers => - render({ - value, - updateValue, - errorToShow, - hoverTooltipHandlers, - disabled, - }) - } - - ) -} - -type ShowFieldErrorParams = { - name: StepFieldName, - focusedField?: StepFieldName, - dirtyFields?: Array, -} -export const showFieldErrors = ({ - name, - focusedField, - dirtyFields, -}: ShowFieldErrorParams): boolean | void | Array => - !(name === focusedField) && dirtyFields && dirtyFields.includes(name) - -const STP = (state: BaseState, ownProps: OP): SP => { - const formData = stepFormSelectors.getUnsavedForm(state) - return { - value: formData ? formData[ownProps.name] : null, - stepType: formData ? formData.stepType : null, - disabled: formData ? getDisabledFields(formData).has(ownProps.name) : false, - } -} - -const DTP = (dispatch: ThunkDispatch<*>, ownProps: OP): DP => ({ - updateValue: (value: mixed) => { - const maskedValue = maskField(ownProps.name, value) - dispatch( - actions.changeFormInput({ update: { [ownProps.name]: maskedValue } }) - ) - }, -}) - -export const FieldConnector: React.AbstractComponent<$Exact> = connect< - StepFieldProps, - $Exact, - SP, - DP, - _, - _ ->( - STP, - DTP -)(FieldConnectorComponent) diff --git a/protocol-designer/src/components/StepEditForm/fields/ToggleRowField.js b/protocol-designer/src/components/StepEditForm/fields/ToggleRowField.js index 3052dc30606..a6b4bdaeae2 100644 --- a/protocol-designer/src/components/StepEditForm/fields/ToggleRowField.js +++ b/protocol-designer/src/components/StepEditForm/fields/ToggleRowField.js @@ -5,28 +5,34 @@ import cx from 'classnames' import { ToggleField } from '@opentrons/components' import styles from '../StepEditForm.css' -import { FieldConnector } from './FieldConnector' -import type { StepFieldName } from '../../../steplist/fieldLevel' + +import type { FieldProps } from '../types' type ToggleRowProps = {| + ...FieldProps, offLabel?: string, onLabel?: string, - name: StepFieldName, className?: string, - disabled?: boolean, |} -export const ToggleRowField = (props: ToggleRowProps): React.Node => ( - ( - ) => updateValue(!value)} - /> - )} - /> -) +export const ToggleRowField = (props: ToggleRowProps): React.Node => { + const { + updateValue, + value, + name, + offLabel, + onLabel, + disabled, + className, + } = props + return ( + ) => updateValue(!value)} + disabled={disabled} + /> + ) +} diff --git a/protocol-designer/src/components/StepEditForm/forms/ThermocyclerForm/StateFields.js b/protocol-designer/src/components/StepEditForm/forms/ThermocyclerForm/StateFields.js index 8755360c2bd..0bcc243cd91 100644 --- a/protocol-designer/src/components/StepEditForm/forms/ThermocyclerForm/StateFields.js +++ b/protocol-designer/src/components/StepEditForm/forms/ThermocyclerForm/StateFields.js @@ -36,7 +36,7 @@ export const StateFields = (props: Props): React.Node => { >
{ >
{ className={styles.toggle_form_group} > { } }) -jest.mock('../../fields/FieldConnector', () => ({ - FieldConnector: () =>
, -})) - const mockStore = { dispatch: jest.fn(), subscribe: jest.fn(), diff --git a/protocol-designer/src/components/StepEditForm/utils.js b/protocol-designer/src/components/StepEditForm/utils.js index ed518ec9266..51351093bf8 100644 --- a/protocol-designer/src/components/StepEditForm/utils.js +++ b/protocol-designer/src/components/StepEditForm/utils.js @@ -1,5 +1,4 @@ // @flow -import * as React from 'react' import difference from 'lodash/difference' import isEqual from 'lodash/isEqual' import without from 'lodash/without' @@ -10,7 +9,6 @@ import { DEST_WELL_BLOWOUT_DESTINATION, } from '../../step-generation/utils' import { getDefaultsForStepType } from '../../steplist/formLevel/getDefaultsForStepType.js' -import styles from './StepEditForm.css' import type { Options } from '@opentrons/components' import type { ProfileFormError } from '../../steplist/formLevel/profileErrors' import type { FormWarning } from '../../steplist/formLevel/warnings' @@ -170,48 +168,6 @@ export const getVisibleProfileFormLevelErrors = (args: {| }) } -// TODO(IL, 2021-02-25): DEPRECATED. this is only used by FieldConnector. Remove in #7298 -export function getTooltipForField( - stepType: ?string, - name: string, - disabled: boolean -): ?React.Node { - if (!stepType) { - console.error( - `expected stepType for form, cannot getTooltipText for ${name}` - ) - return null - } - - const prefixes = ['aspirate_', 'dispense_'] - const nameWithoutPrefix = prefixes.some(prefix => name.startsWith(prefix)) - ? name.split('_').slice(1).join('_') - : name - - // NOTE: this is a temporary solution until we want to be able to choose from - // multiple tooltips for the same field depending on form state. - // As-is, this will only let us show two tooltips for any given field per step type: - // non-disabled tooltip copy, and disabled tooltip copy. - const disabledKeys = disabled - ? [ - `tooltip.step_fields.${stepType}.disabled.${name}`, - `tooltip.step_fields.${stepType}.disabled.$generic`, - ] - : [] - - // specificity cascade for names. - // first level: "disabled" wins out if disabled arg is true - // second level: prefix. "aspirate_foo" wins over "foo" - const text: string = i18n.t([ - ...disabledKeys, - `tooltip.step_fields.defaults.${name}`, - `tooltip.step_fields.defaults.${nameWithoutPrefix}`, - '', - ]) - - return text ?
{text}
: null -} - export const getFieldDefaultTooltip = (name: string): string => i18n.t([`tooltip.step_fields.defaults.${name}`, ''])