Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Protocol-designer, components, step-generation): multi tiprack support #13166

Closed
wants to merge 12 commits into from
5 changes: 2 additions & 3 deletions components/src/instrument/InfoItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as React from 'react'

import styles from './instrument.css'

export interface InfoItemProps {
title: string
title: string | null
value: string
className?: string
}
Expand All @@ -17,7 +16,7 @@ export function InfoItem(props: InfoItemProps): JSX.Element {

return (
<div className={className}>
<h2 className={styles.title}>{title}</h2>
{title != null ? <h2 className={styles.title}>{title}</h2> : null}
<span className={styles.value}>{value}</span>
</div>
)
Expand Down
13 changes: 9 additions & 4 deletions components/src/instrument/InstrumentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/** human-readable description, eg 'p300 Single-channel' */
description: string
/** paired tiprack model */
tiprackModel?: string
tiprackModels?: string[]
/** if disabled, pipette & its info are grayed out */
isDisabled: boolean
/** specs of mounted pipette */
Expand Down Expand Up @@ -47,9 +47,14 @@
title={props.showMountLabel ? `${props.mount} pipette` : 'pipette'}
value={props.description}
/>
{props.tiprackModel && (
<InfoItem title="tip rack" value={props.tiprackModel} />
)}
{props.tiprackModels &&
props.tiprackModels.map((model, index) => (
<InfoItem

Check warning on line 52 in components/src/instrument/InstrumentInfo.tsx

View check run for this annotation

Codecov / codecov/patch

components/src/instrument/InstrumentInfo.tsx#L52

Added line #L52 was not covered by tests
key={index}
title={index === 0 ? 'tip racks' : null}
value={model}
/>
))}
</Flex>
{props.children}
{props.mount === LEFT && props.pipetteSpecs && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ describe('FileSidebar', () => {
pipetteLeftId: {
name: 'string' as any,
id: pipetteLeftId,
tiprackDefURI: 'test',
tiprackLabwareDef: fixture_tiprack_10_ul as LabwareDefinition2,
tiprackDefURI: ['test'],
tiprackLabwareDef: [fixture_tiprack_10_ul as LabwareDefinition2],
spec: fixtureP10Single,
mount: 'left',
},
pipetteRightId: {
name: 'string' as any,
id: pipetteRightId,
tiprackDefURI: 'test',
tiprackLabwareDef: fixture_tiprack_10_ul as LabwareDefinition2,
tiprackDefURI: ['test'],
tiprackLabwareDef: [fixture_tiprack_10_ul as LabwareDefinition2],
spec: fixtureP300Single,
mount: 'right',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
}

.large_field {
width: 12rem;
width: 13rem;
}

.small_field {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ interface OP {
propsForFields: FieldPropsByName
stepType: StepType
volume: string | null
tipRack?: string | null
}
type Props = SP & OP

Expand Down Expand Up @@ -114,6 +115,7 @@ const mapSTP = (state: BaseState, ownProps: OP): SP => {
pipette,
stepType,
volume,
tipRack,
} = ownProps

const blowoutLocationOptions = getBlowoutLocationOptionsForForm({
Expand All @@ -132,6 +134,7 @@ const mapSTP = (state: BaseState, ownProps: OP): SP => {
path,
pipette,
volume,
tipRack,
},
stepFormSelectors.getPipetteEntities(state)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface ValuesForPath {
dispense_wells?: string[] | null
pipette?: string | null
volume?: string | null
tipRack?: string | null
}
export function getDisabledPathMap(
values: ValuesForPath,
Expand All @@ -27,6 +28,7 @@ export function getDisabledPathMap(
changeTip,
dispense_wells,
pipette,
tipRack,
} = values
if (!pipette) return null
const wellRatio = getWellRatio(aspirate_wells, dispense_wells)
Expand All @@ -51,7 +53,8 @@ export function getDisabledPathMap(

// transfer volume overwrites change tip disable reasoning
const pipetteEntity = pipetteEntities[pipette]
const pipetteCapacity = pipetteEntity && getPipetteCapacity(pipetteEntity)
const pipetteCapacity =
pipetteEntity && getPipetteCapacity(pipetteEntity, tipRack)
const volume = Number(values.volume)
const airGapChecked = aspirate_airGap_checkbox
let airGapVolume = airGapChecked ? Number(values.aspirate_airGap_volume) : 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function mapSTP(state: BaseState, ownProps: OP): SP {
dispense_wells,
pipette,
volume,
tipRack,
} = ownProps
const pipetteEntities = stepFormSelectors.getPipetteEntities(state)
const disabledPathMap = getDisabledPathMap(
Expand All @@ -30,6 +31,7 @@ function mapSTP(state: BaseState, ownProps: OP): SP {
dispense_wells,
pipette,
volume,
tipRack,
},
pipetteEntities
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react'
import { DropdownField, Options } from '@opentrons/components'
import cx from 'classnames'
import { DropdownField, Options } from '@opentrons/components'
import styles from '../StepEditForm.css'
import { StepFieldName } from '../../../steplist/fieldLevel'
import { FieldProps } from '../types'
import type { StepFieldName } from '../../../steplist/fieldLevel'
import type { FieldProps } from '../types'

export interface StepFormDropdownProps extends FieldProps {
options: Options
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react'
import { connect } from 'react-redux'
import { FormGroup, DropdownField, Options } from '@opentrons/components'
import { selectors as uiLabwareSelectors } from '../../../ui/labware'
import { i18n } from '../../../localization'
import styles from '../StepEditForm.css'

import type { BaseState } from '../../../types'
import type { FieldProps } from '../types'

interface SP {
options: Options
}
type Props = FieldProps & SP

const TiprackFieldSTP = (state: BaseState): SP => ({
options: uiLabwareSelectors.getTiprackOptions(state),
})

export const TiprackField = connect(TiprackFieldSTP)((props: Props) => {
return (
<FormGroup
label={i18n.t('form.step_edit_form.tipRack')}
className={styles.large_field}
>
<DropdownField
options={props.options}
name={props.name}
value={String(props.options[0].value)}
onBlur={props.onFieldBlur}
onFocus={props.onFieldFocus}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
props.updateValue(e.currentTarget.value)

Check warning on line 33 in protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx

View check run for this annotation

Codecov / codecov/patch

protocol-designer/src/components/StepEditForm/fields/TiprackField.tsx#L33

Added line #L33 was not covered by tests
}}
/>
</FormGroup>
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { DelayFields } from './DelayFields'
export { DisposalVolumeField } from './DisposalVolumeField'
export { FlowRateField } from './FlowRateField'
export { LabwareField } from './LabwareField'
export { TiprackField } from './TiprackField'
export { LabwareLocationField } from './LabwareLocationField'
export { PathField } from './PathField'
export { PipetteField } from './PipetteField'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
WellOrderField,
WellSelectionField,
} from '../fields'
import { TiprackField } from '../fields/TiprackField'
import {
getBlowoutLocationOptionsForForm,
getLabwareFieldForPositioningField,
Expand All @@ -33,7 +34,6 @@ export const MixForm = (props: StepFormProps): JSX.Element => {

const toggleCollapsed = (): void =>
setCollapsed(prevCollapsed => !prevCollapsed)

return (
<div className={styles.form_wrapper}>
<div className={styles.section_header}>
Expand All @@ -43,6 +43,7 @@ export const MixForm = (props: StepFormProps): JSX.Element => {
</div>
<div className={styles.form_row}>
<PipetteField {...propsForFields.pipette} />
<TiprackField {...propsForFields.tipRack} />
<VolumeField
{...propsForFields.volume}
label={i18n.t('form.step_edit_form.mixVolumeLabel')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ import {
TOOLTIP_FIXED,
useHoverTooltip,
} from '@opentrons/components'
import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data'
import { i18n } from '../../../../localization'
import { getRobotType } from '../../../../file-data/selectors'
import { getAdditionalEquipment } from '../../../../step-forms/selectors'
import {
LabwareField,
LabwareLocationField,
CheckboxRowField,
} from '../../fields'
import styles from '../../StepEditForm.css'
import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data'
import { getRobotType } from '../../../../file-data/selectors'
import { getAdditionalEquipment } from '../../../../step-forms/selectors'

import type { StepFormProps } from '../../types'

export const MoveLabwareForm = (props: StepFormProps): JSX.Element => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ChangeTipField,
DisposalVolumeField,
PathField,
TiprackField,
} from '../../fields'
import styles from '../../StepEditForm.css'
import { StepFormProps } from '../../types'
Expand All @@ -23,7 +24,6 @@ export const MoveLiquidForm = (props: StepFormProps): JSX.Element => {

const { propsForFields, formData } = props
const { stepType, path } = formData

return (
<div className={styles.form_wrapper}>
<div className={styles.section_header}>
Expand All @@ -33,6 +33,7 @@ export const MoveLiquidForm = (props: StepFormProps): JSX.Element => {
</div>
<div className={styles.form_row}>
<PipetteField {...propsForFields.pipette} />
<TiprackField {...propsForFields.tipRack} />
<VolumeField
{...propsForFields.volume}
label={i18n.t('form.step_edit_form.field.volume.label')}
Expand Down Expand Up @@ -102,6 +103,7 @@ export const MoveLiquidForm = (props: StepFormProps): JSX.Element => {
dispense_wells={formData.dispense_wells}
pipette={formData.pipette}
volume={formData.volume}
tipRack={formData.tipRack}
/>
</div>
<div className={cx(styles.section_column, styles.disposal_vol_wrapper)}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import * as React from 'react'
import { mount, ReactWrapper } from 'enzyme'
import { Provider } from 'react-redux'
import { MixForm } from '../MixForm'
import { AspDispSection } from '../AspDispSection'
import * as stepFormSelectors from '../../../../step-forms/selectors'
import { getTiprackOptions } from '../../../../ui/labware/selectors'
import { FormData } from '../../../../form-types'
import { WellOrderField } from '../../fields'
import { MixForm } from '../MixForm'
import { AspDispSection } from '../AspDispSection'

const { DelayFields } = jest.requireActual('../../fields')

jest.mock('../../../../step-forms/selectors')
jest.mock('../../../../ui/labware/selectors')

const getUnsavedFormMock = stepFormSelectors.getUnsavedForm as jest.MockedFunction<
typeof stepFormSelectors.getUnsavedForm
>

const mockGetTiprackOptions = getTiprackOptions as jest.MockedFunction<
typeof getTiprackOptions
>

jest.mock('../../fields/', () => {
const actualFields = jest.requireActual('../../fields')

Expand All @@ -28,6 +34,7 @@ jest.mock('../../fields/', () => {
TipPositionField: () => <div></div>,
WellOrderField: () => <div></div>,
WellSelectionField: () => <div></div>,
TiprackField: () => <div></div>,
}
})

Expand Down Expand Up @@ -56,7 +63,9 @@ describe('MixForm', () => {
getUnsavedFormMock.mockReturnValue({
stepType: 'mix',
} as FormData)

mockGetTiprackOptions.mockReturnValue([
{ name: 'mockName', value: 'mockValue' },
])
props = {
formData: {
stepType: 'mix',
Expand Down Expand Up @@ -97,6 +106,15 @@ describe('MixForm', () => {
updateValue: jest.fn() as any,
value: null,
},
tipRack: {
onFieldFocus: jest.fn() as any,
onFieldBlur: jest.fn() as any,
errorToShow: null,
disabled: false,
name: 'tipRack',
updateValue: jest.fn() as any,
value: null,
},
},
}
})
Expand Down
Loading
Loading