Skip to content

Commit

Permalink
feat(protocol-designer): edit additional items staging area support (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader authored Oct 16, 2023
1 parent d16b7ec commit 014c0ca
Show file tree
Hide file tree
Showing 24 changed files with 788 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface EquipmentOptionProps extends StyleProps {
text: React.ReactNode
image?: React.ReactNode
showCheckbox?: boolean
disabled?: boolean
}
export function EquipmentOption(props: EquipmentOptionProps): JSX.Element {
const {
Expand All @@ -26,6 +27,7 @@ export function EquipmentOption(props: EquipmentOptionProps): JSX.Element {
isSelected,
image = null,
showCheckbox = false,
disabled = false,
...styleProps
} = props
return (
Expand All @@ -34,10 +36,13 @@ export function EquipmentOption(props: EquipmentOptionProps): JSX.Element {
alignItems={ALIGN_CENTER}
width="21.75rem"
padding={SPACING.spacing8}
border={isSelected ? BORDERS.activeLineBorder : BORDERS.lineBorder}
border={
isSelected && !disabled ? BORDERS.activeLineBorder : BORDERS.lineBorder
}
borderRadius={BORDERS.borderRadiusSize2}
cursor="pointer"
onClick={onClick}
cursor={disabled ? 'auto' : 'pointer'}
backgroundColor={disabled ? COLORS.darkGreyDisabled : COLORS.transparent}
onClick={disabled ? undefined : onClick}
{...styleProps}
>
{showCheckbox ? (
Expand All @@ -57,7 +62,11 @@ export function EquipmentOption(props: EquipmentOptionProps): JSX.Element {
>
{image}
</Flex>
<Text as="p" fontSize={TYPOGRAPHY.fontSizeP}>
<Text
as="p"
fontSize={TYPOGRAPHY.fontSizeP}
color={disabled ? COLORS.errorDisabled : COLORS.darkBlackEnabled}
>
{text}
</Text>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const DEFAULT_SLOT_MAP: { [moduleModel in ModuleModel]?: string } = {
[THERMOCYCLER_MODULE_V2]: 'B1',
[HEATERSHAKER_MODULE_V1]: 'D1',
[MAGNETIC_BLOCK_V1]: 'D2',
[TEMPERATURE_MODULE_V2]: 'D3',
[TEMPERATURE_MODULE_V2]: 'C1',
}

interface FlexModuleFieldsProps extends WizardTileProps {
Expand All @@ -220,6 +220,14 @@ function FlexModuleFields(props: FlexModuleFieldsProps): JSX.Element {
const { values, setFieldValue, enableDeckModification } = props

const isFlex = values.fields.robotType === FLEX_ROBOT_TYPE
const allStagingAreasInUse =
values.additionalEquipment.filter(equipment =>
equipment.includes('stagingArea')
).length === 4
const allModulesInSideSlotsOnDeck =
values.modulesByType.heaterShakerModuleType.onDeck &&
values.modulesByType.thermocyclerModuleType.onDeck &&
values.modulesByType.temperatureModuleType.onDeck

const handleSetEquipmentOption = (equipment: AdditionalEquipment): void => {
if (values.additionalEquipment.includes(equipment)) {
Expand All @@ -241,6 +249,7 @@ function FlexModuleFields(props: FlexModuleFieldsProps): JSX.Element {
const moduleType = getModuleType(moduleModel)
return (
<EquipmentOption
// TODO(jr, 10/10/23): add disabled option here for if the deck is full
key={moduleModel}
isSelected={values.modulesByType[moduleType].onDeck}
image={<ModuleDiagram type={moduleType} model={moduleModel} />}
Expand Down Expand Up @@ -302,6 +311,7 @@ function FlexModuleFields(props: FlexModuleFieldsProps): JSX.Element {
}
text="Trash Bin"
showCheckbox
disabled={allStagingAreasInUse && allModulesInSideSlotsOnDeck}
/>
</>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ describe('EquipmentOption', () => {
const { getByText } = render(props)
getByText('mockText')
})
it('renders the equipment option that is disabled', () => {
props = {
...props,
disabled: true,
}
const { getByLabelText } = render(props)
expect(getByLabelText('EquipmentOption_flex_mockText')).toHaveStyle(
`background-color: ${COLORS.darkGreyDisabled}`
)
})
it('renders the equipment option without check not selected and image', () => {
props = {
...props,
Expand Down
55 changes: 33 additions & 22 deletions protocol-designer/src/components/modals/CreateFileWizard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ import { ModulesAndOtherTile } from './ModulesAndOtherTile'
import { WizardHeader } from './WizardHeader'
import { StagingAreaTile } from './StagingAreaTile'

import type { NormalizedPipette } from '@opentrons/step-generation'
import {
NormalizedPipette,
OT_2_TRASH_DEF_URI,
} from '@opentrons/step-generation'
import type { FormState } from './types'

type WizardStep =
Expand Down Expand Up @@ -195,6 +198,8 @@ export function CreateFileWizard(): JSX.Element | null {
},
})
)

// add trash
if (
enableDeckModification &&
values.additionalEquipment.includes('trashBin')
Expand All @@ -207,15 +212,39 @@ export function CreateFileWizard(): JSX.Element | null {
})
)
}

if (!enableDeckModification) {
if (
!enableDeckModification ||
(enableDeckModification && values.fields.robotType === OT2_ROBOT_TYPE)
) {
dispatch(
labwareIngredActions.createContainer({
labwareDefURI: FLEX_TRASH_DEF_URI,
labwareDefURI:
values.fields.robotType === FLEX_ROBOT_TYPE
? FLEX_TRASH_DEF_URI
: OT_2_TRASH_DEF_URI,
slot: values.fields.robotType === FLEX_ROBOT_TYPE ? 'A3' : '12',
})
)
}

// add waste chute
if (
enableDeckModification &&
values.additionalEquipment.includes('wasteChute')
) {
dispatch(createDeckFixture('wasteChute', WASTE_CHUTE_SLOT))
}
// add staging areas
const stagingAreas = values.additionalEquipment.filter(equipment =>
equipment.includes('stagingArea')
)
if (enableDeckModification && stagingAreas.length > 0) {
stagingAreas.forEach(stagingArea => {
const [, location] = stagingArea.split('_')
dispatch(createDeckFixture('stagingArea', location))
})
}

// create modules
modules.forEach(moduleArgs =>
dispatch(stepFormActions.createModule(moduleArgs))
Expand All @@ -235,24 +264,6 @@ export function CreateFileWizard(): JSX.Element | null {
})
)
})

// add waste chute
if (
enableDeckModification &&
values.additionalEquipment.includes('wasteChute')
) {
dispatch(createDeckFixture('wasteChute', WASTE_CHUTE_SLOT))
}
// add staging areas
const stagingAreas = values.additionalEquipment.filter(equipment =>
equipment.includes('stagingArea')
)
if (enableDeckModification && stagingAreas.length > 0) {
stagingAreas.forEach(stagingArea => {
const [, location] = stagingArea.split('_')
dispatch(createDeckFixture('stagingArea', location))
})
}
}
}
const wizardHeader = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const EditModulesModal = (props: EditModulesModalProps): JSX.Element => {
const isSlotBlocked = getSlotIdsBlockedBySpanning(
initialDeckSetup
).includes(selectedSlot)
const isSlotEmpty = getSlotIsEmpty(initialDeckSetup, selectedSlot)
const isSlotEmpty = getSlotIsEmpty(initialDeckSetup, selectedSlot, true)
const labwareOnSlot = getLabwareOnSlot(initialDeckSetup, selectedSlot)
const isLabwareCompatible =
labwareOnSlot && getLabwareIsCompatible(labwareOnSlot.def, moduleType)
Expand Down
151 changes: 77 additions & 74 deletions protocol-designer/src/components/modules/AdditionalItemsRow.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import * as React from 'react'
import styled from 'styled-components'
import { FLEX_ROBOT_TYPE, WASTE_CHUTE_SLOT } from '@opentrons/shared-data'
import { WASTE_CHUTE_SLOT } from '@opentrons/shared-data'
import {
OutlineButton,
Flex,
JUSTIFY_SPACE_BETWEEN,
DIRECTION_COLUMN,
LabeledValue,
SPACING,
SlotMap,
Tooltip,
useHoverTooltip,
Box,
Expand All @@ -19,6 +18,8 @@ import { i18n } from '../../localization'
import gripperImage from '../../images/flex_gripper.png'
import { Portal } from '../portals/TopPortal'
import { TrashModal } from './TrashModal'
import { FlexSlotMap } from './FlexSlotMap'

import styles from './styles.css'

interface AdditionalItemsRowProps {
Expand Down Expand Up @@ -59,92 +60,94 @@ export function AdditionalItemsRow(
/>
</Portal>
) : null}
<Flex justifyContent={JUSTIFY_SPACE_BETWEEN} height="7rem">
<Flex flexDirection={DIRECTION_COLUMN}>
<h4 className={styles.row_title}>
{i18n.t(`modules.additional_equipment_display_names.${name}`)}
</h4>
<Flex flexDirection={DIRECTION_COLUMN}>
<h4 className={styles.row_title}>
{i18n.t(`modules.additional_equipment_display_names.${name}`)}
</h4>

<Flex justifyContent={JUSTIFY_SPACE_BETWEEN}>
<AdditionalItemImage
// TODO(jr, 9/13/23): update this image to the waste chute and trash asset
src={gripperImage}
alt={i18n.t(`modules.additional_equipment_display_names.${name}`)}
/>
</Flex>
<div
className={styles.module_col}
style={{ marginLeft: SPACING.spacing32 }}
>
{isEquipmentAdded && name === 'gripper' ? (
<LabeledValue
label="Model"
value={i18n.t(`modules.model_display_name.gripperV1`)}
/>
) : null}
</div>

{isEquipmentAdded && name !== 'gripper' ? (
<>
<div className={styles.module_col}>
<div
className={styles.module_col}
style={{ marginLeft: SPACING.spacing32 }}
>
{isEquipmentAdded && name === 'gripper' ? (
<LabeledValue
label="Position"
value={`Slot ${
name === 'trashBin' ? trashBinSlot : WASTE_CHUTE_SLOT
}`}
/>
</div>
<div className={styles.slot_map}>
<SlotMap
occupiedSlots={
name === 'trashBin' && trashBinSlot != null
? [trashBinSlot]
: [WASTE_CHUTE_SLOT]
}
collisionSlots={[]}
robotType={FLEX_ROBOT_TYPE}
label="Model"
value={i18n.t(`modules.model_display_name.gripperV1`)}
/>
</div>
</>
) : null}
) : null}
</div>

<Box
flexDirection={DIRECTION_ROW}
flex="1 0 40%"
textAlign={TYPOGRAPHY.textAlignRight}
>
{name === 'trashBin' && isEquipmentAdded ? (
<OutlineButton
onClick={() => openTrashModal(true)}
className={styles.module_button}
>
{i18n.t('shared.edit')}
</OutlineButton>
{isEquipmentAdded && name !== 'gripper' ? (
<>
<div className={styles.module_col}>
<LabeledValue
label="Position"
value={`Slot ${
name === 'trashBin' ? trashBinSlot : WASTE_CHUTE_SLOT
}`}
/>
</div>
<div className={styles.slot_map}>
<FlexSlotMap
selectedSlots={
name === 'trashBin'
? [trashBinSlot ?? '']
: [WASTE_CHUTE_SLOT]
}
/>
</div>
</>
) : null}

<Box
{...targetProps}
width="6.75rem"
display="inline-block"
marginRight={SPACING.spacing16}
flexDirection={DIRECTION_ROW}
flex="1 0 40%"
textAlign={TYPOGRAPHY.textAlignRight}
>
<OutlineButton
className={styles.module_button}
disabled={disabledRemoveButton}
onClick={addTrash ? () => openTrashModal(true) : handleAttachment}
{name === 'trashBin' && isEquipmentAdded ? (
<OutlineButton
onClick={() => openTrashModal(true)}
className={styles.module_button}
>
{i18n.t('shared.edit')}
</OutlineButton>
) : null}
<Box
{...targetProps}
width="6.75rem"
display="inline-block"
marginRight={SPACING.spacing16}
>
{isEquipmentAdded
? i18n.t('shared.remove')
: i18n.t('shared.add')}
</OutlineButton>
<OutlineButton
className={styles.module_button}
disabled={disabledRemoveButton}
onClick={
addTrash ? () => openTrashModal(true) : handleAttachment
}
>
{isEquipmentAdded
? i18n.t('shared.remove')
: i18n.t('shared.add')}
</OutlineButton>
</Box>
{disabledRemoveButton ? (
<Tooltip
{...tooltipProps}
width="10rem"
textAlign={TYPOGRAPHY.textAlignCenter}
>
{i18n.t(`tooltip.disabled_cannot_delete_trash`)}
</Tooltip>
) : null}
</Box>
{disabledRemoveButton ? (
<Tooltip
{...tooltipProps}
width="10rem"
textAlign={TYPOGRAPHY.textAlignCenter}
>
{i18n.t(`tooltip.disabled_cannot_delete_trash`)}
</Tooltip>
) : null}
</Box>
</Flex>
</Flex>
</>
)
Expand Down
Loading

0 comments on commit 014c0ca

Please sign in to comment.