From bd383369d8d2033d01afa449cd8115b7cfc4815f Mon Sep 17 00:00:00 2001 From: Brent Hagen Date: Thu, 7 Dec 2023 17:03:11 -0500 Subject: [PATCH] feat(components): adapt deck location select for OT-2 deck definition v4 (#14078) implements the v4 version of deck location select for OT-2. used by drop tip wizard. uses v3 DeckFromLayers in the same way as BaseDeck. closes RQA-1951 --- .../hardware-sim/DeckSlotLocation/index.tsx | 224 ++++-------------- .../src/hooks/useSelectDeckLocation/index.tsx | 102 +++++--- shared-data/js/fixtures.ts | 1 + 3 files changed, 119 insertions(+), 208 deletions(-) diff --git a/components/src/hardware-sim/DeckSlotLocation/index.tsx b/components/src/hardware-sim/DeckSlotLocation/index.tsx index 6f24bebf90f..79397c72a74 100644 --- a/components/src/hardware-sim/DeckSlotLocation/index.tsx +++ b/components/src/hardware-sim/DeckSlotLocation/index.tsx @@ -1,207 +1,73 @@ import * as React from 'react' -import { DeckDefinition, DeckSlot, ModuleType } from '@opentrons/shared-data' +import { getPositionFromSlotId, OT2_ROBOT_TYPE } from '@opentrons/shared-data' +import ot2DeckDefV4 from '@opentrons/shared-data/deck/definitions/4/ot2_standard.json' -// TODO(BC, 8/2/2023): as soon as the deck definitions have a concept of base locations, use their -// identity to key this mapping instead of slotNames -interface DeckSlotLocationProps extends React.SVGProps { +import { SlotBase } from '../BaseDeck/SlotBase' + +import type { + DeckDefinition, + DeckSlot, + RobotType, +} from '@opentrons/shared-data' + +interface LegacyDeckSlotLocationProps extends React.SVGProps { + robotType: RobotType slotName: DeckSlot['id'] - deckDefinition: DeckDefinition - moduleType?: ModuleType slotBaseColor?: React.SVGProps['fill'] slotClipColor?: React.SVGProps['stroke'] - showExtensions?: boolean } -// TODO(bh, 2023-10-11): replace usage of this component with base deck fixtures -export function DeckSlotLocation( - props: DeckSlotLocationProps +/** + * This is a legacy component for rendering an OT-2 deck slot by reference to the V4 deck definition + */ +export function LegacyDeckSlotLocation( + props: LegacyDeckSlotLocationProps ): JSX.Element | null { const { + robotType, slotName, - deckDefinition, slotBaseColor, slotClipColor, - showExtensions = false, ...restProps } = props - const slotDef = deckDefinition?.locations.addressableAreas.find( + if (robotType !== OT2_ROBOT_TYPE) return null + + const slotDef = ot2DeckDefV4.locations.addressableAreas.find( s => s.id === slotName ) if (slotDef == null) { console.warn( - `cannot render DeckSlotLocation, no deck slot named: ${slotName} in deck def ${deckDefinition?.otId}` + `cannot render DeckSlotLocation, no deck slot named: ${slotName} in OT-2 deck definition` ) return null } - const contentsBySlotName: { [slotName: string]: JSX.Element } = { - A1: ( - <> - {showExtensions ? ( - - ) : null} - - - - - - - ), - A2: ( - <> - - , - , - , - - - ), - A3: ( - <> - - , - , - , - - - ), - B1: ( - <> - - , - , - , - - - ), - B2: ( - <> - - , - , - , - - - ), - B3: ( - <> - - , - , - , - - - ), - C1: ( - <> - - - - - - - ), - C2: ( - <> - - , - , - , - - - ), - C3: ( - <> - - , - , - , - - - ), - D1: ( - <> - - - - - - - ), - D2: ( - <> - - - - - - - ), - D3: ( - <> - - - - - - - ), - } + const slotPosition = getPositionFromSlotId( + slotName, + (ot2DeckDefV4 as unknown) as DeckDefinition + ) - return {contentsBySlotName[slotName]} -} + const [xPosition, yPosition] = slotPosition ?? [0, 0] + const { xDimension, yDimension } = slotDef.boundingBox + + const isFixedTrash = slotName === 'fixedTrash' + + // adjust the fixed trash position and dimension + const fixedTrashPositionAdjustment = isFixedTrash ? 7 : 0 + const fixedTrashDimensionAdjustment = isFixedTrash ? -9 : 0 + + const adjustedXPosition = xPosition + fixedTrashPositionAdjustment + const adjustedYPosition = yPosition + fixedTrashPositionAdjustment + const adjustedXDimension = xDimension + fixedTrashDimensionAdjustment + const adjustedYDimension = yDimension + fixedTrashDimensionAdjustment -function SlotBase(props: React.SVGProps): JSX.Element { - return -} -function SlotClip(props: React.SVGProps): JSX.Element { return ( - + + + ) } diff --git a/components/src/hooks/useSelectDeckLocation/index.tsx b/components/src/hooks/useSelectDeckLocation/index.tsx index 6a801765a33..c9cebf7f5c7 100644 --- a/components/src/hooks/useSelectDeckLocation/index.tsx +++ b/components/src/hooks/useSelectDeckLocation/index.tsx @@ -3,12 +3,16 @@ import isEqual from 'lodash/isEqual' import { FLEX_CUTOUT_BY_SLOT_ID, + FLEX_ROBOT_TYPE, getDeckDefFromRobotType, getPositionFromSlotId, isAddressableAreaStandardSlot, + OT2_ROBOT_TYPE, } from '@opentrons/shared-data' import { + DeckFromLayers, + LegacyDeckSlotLocation, RobotCoordinateSpace, RobotCoordsForeignDiv, SingleSlotFixture, @@ -17,7 +21,7 @@ import { import { Icon } from '../../icons' import { Text } from '../../primitives' import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles' -import { COLORS, SPACING } from '../../ui-style-constants' +import { COLORS, SPACING, TYPOGRAPHY } from '../../ui-style-constants' import type { DeckDefinition, @@ -31,6 +35,17 @@ const X_CROP_MM = 0 const X_ADJUSTMENT_FOR_TC = '-50' const Y_ADJUSTMENT_FOR_TC = '214' +const OT2_DECK_LOCATION_SELECT_LAYER_BLOCK_LIST: string[] = [ + 'calibrationMarkings', + 'fixedBase', + 'doorStops', + 'metalFrame', + 'removalHandle', + 'removableDeckOutline', + 'screwHoles', + 'slotNumbers', +] + export function useDeckLocationSelect( robotType: RobotType, theme?: DeckLocationSelectThemes @@ -68,6 +83,8 @@ export function DeckLocationSelect({ theme = 'default', isThermocycler = false, }: DeckLocationSelectProps): JSX.Element { + const robotType = deckDef.robot.model + return ( {deckDef.locations.addressableAreas // only render standard slot fixture components - .filter(addressableArea => - isAddressableAreaStandardSlot(addressableArea.id, deckDef) + .filter( + addressableArea => + isAddressableAreaStandardSlot(addressableArea.id, deckDef) || + // special case the OT-2 trash addressable area + addressableArea.id === 'fixedTrash' ) .map(slot => { const slotLocation = { slotName: slot.id } @@ -129,23 +149,42 @@ export function DeckLocationSelect({ const cutoutId = FLEX_CUTOUT_BY_SLOT_ID[slot.id] return ( - - - !isDisabled && - setSelectedLocation != null && - setSelectedLocation(slotLocation) - } - cursor={ - setSelectedLocation == null || isDisabled || isSelected - ? 'default' - : 'pointer' - } - deckDefinition={deckDef} - /> + + {robotType === FLEX_ROBOT_TYPE ? ( + + !isDisabled && + setSelectedLocation != null && + setSelectedLocation(slotLocation) + } + cursor={ + setSelectedLocation == null || isDisabled || isSelected + ? 'default' + : 'pointer' + } + deckDefinition={deckDef} + /> + ) : ( + + !isDisabled && + setSelectedLocation != null && + setSelectedLocation(slotLocation) + } + cursor={ + setSelectedLocation == null || isDisabled || isSelected + ? 'default' + : 'pointer' + } + /> + )} {isSelected && slotPosition != null ? ( - - + css={ + robotType === FLEX_ROBOT_TYPE + ? TYPOGRAPHY.level4HeaderSemiBold + : TYPOGRAPHY.bodyTextSemiBold + } + > Selected @@ -167,10 +208,13 @@ export function DeckLocationSelect({ ) })} - + {robotType === OT2_ROBOT_TYPE ? ( + + ) : null} + ) } diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index cbfd463ab7d..64413d130c8 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -33,6 +33,7 @@ export const OT2_CUTOUT_BY_SLOT_ID: { [slotId: string]: OT2Cutout } = { 9: 'cutout9', 10: 'cutout10', 11: 'cutout11', + fixedTrash: 'cutout12', } // mapping of Flex deck slots to cutouts