From b2d1066d26b19a09bb80352037ccce72c3b781b5 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:27:46 -0500 Subject: [PATCH] fix(protocol-designer): deck setup slot details responsiveness (#16862) closes RQA-3602 RQA-3327 --- .../ListItemChildren/ListItemDescriptor.tsx | 16 +++- .../RobotCoordinateSpaceWithRef.tsx | 12 +-- .../__tests__/utils.test.ts | 25 ------ .../organisms/SlotDetailsContainer/index.tsx | 29 +------ .../organisms/SlotDetailsContainer/utils.ts | 82 ------------------- .../src/organisms/SlotInformation/index.tsx | 46 +++++++++-- .../Designer/DeckSetup/DeckSetupContainer.tsx | 52 ++++++++++-- .../Designer/DeckSetup/SlotOverflowMenu.tsx | 7 +- .../src/pages/Designer/DeckSetup/utils.ts | 34 ++++++++ .../src/pages/Designer/index.tsx | 2 +- 10 files changed, 138 insertions(+), 167 deletions(-) delete mode 100644 protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts delete mode 100644 protocol-designer/src/organisms/SlotDetailsContainer/utils.ts diff --git a/components/src/atoms/ListItem/ListItemChildren/ListItemDescriptor.tsx b/components/src/atoms/ListItem/ListItemChildren/ListItemDescriptor.tsx index dcedecaa9f8..7b7620457c2 100644 --- a/components/src/atoms/ListItem/ListItemChildren/ListItemDescriptor.tsx +++ b/components/src/atoms/ListItem/ListItemChildren/ListItemDescriptor.tsx @@ -1,7 +1,9 @@ import { Flex } from '../../../primitives' import { ALIGN_FLEX_START, + DIRECTION_COLUMN, DIRECTION_ROW, + JUSTIFY_FLEX_START, JUSTIFY_SPACE_BETWEEN, } from '../../../styles' import { SPACING } from '../../../ui-style-constants' @@ -10,19 +12,27 @@ interface ListItemDescriptorProps { type: 'default' | 'large' description: JSX.Element content: JSX.Element + changeFlexDirection?: boolean } export const ListItemDescriptor = ( props: ListItemDescriptorProps ): JSX.Element => { - const { description, content, type } = props + const { description, content, type, changeFlexDirection = false } = props + let justifyContent = 'none' + if (type === 'default' && changeFlexDirection) { + justifyContent = JUSTIFY_FLEX_START + } else if (type === 'default') { + justifyContent = JUSTIFY_SPACE_BETWEEN + } + return ( {description} diff --git a/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx b/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx index a777299fb1c..78ab942ed47 100644 --- a/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx +++ b/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx @@ -34,17 +34,7 @@ export function RobotCoordinateSpaceWithRef( (acc, deckSlot) => ({ ...acc, [deckSlot.id]: deckSlot }), {} ) - - const PADDING = deckDef.otId === 'ot2_standard' ? 5 : 10 - if (deckDef.otId === 'ot2_standard') { - wholeDeckViewBox = `${viewBoxOriginX - PADDING} ${ - viewBoxOriginY + PADDING * 5 - } ${deckXDimension + PADDING * 2} ${deckYDimension - PADDING * 10}` - } else { - wholeDeckViewBox = `${viewBoxOriginX + PADDING * 2} ${ - viewBoxOriginY - PADDING - } ${deckXDimension + PADDING * 4} ${deckYDimension + PADDING * 3}` - } + wholeDeckViewBox = `${viewBoxOriginX} ${viewBoxOriginY} ${deckXDimension} ${deckYDimension}` } return ( diff --git a/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts b/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts deleted file mode 100644 index eef8e3153c2..00000000000 --- a/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' -import { getXPosition } from '../utils' - -describe('getXPosition', () => { - it('should return the right position 600 for FLEX robot type and slot 3', () => { - expect(getXPosition('3', FLEX_ROBOT_TYPE, false)).toBe('600') - }) - - it('should return the right position 700 for FLEX robot type and slot 4', () => { - expect(getXPosition('4', FLEX_ROBOT_TYPE, true)).toBe('700') - }) - - it('should return the left position for FLEX robot type and slot 1', () => { - expect(getXPosition('1', FLEX_ROBOT_TYPE, false)).toBe('-400') - }) - - it('should return the right position for OT2 robot type and slot 6', () => { - expect(getXPosition('6', OT2_ROBOT_TYPE, false)).toBe('420') - }) - - it('should return the left position for OT2 robot type and slot 2', () => { - expect(getXPosition('2', OT2_ROBOT_TYPE, false)).toBe('-300') - }) -}) diff --git a/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx b/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx index b0b408a4964..4a8403bdf90 100644 --- a/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx +++ b/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx @@ -1,20 +1,15 @@ -import { useLocation } from 'react-router-dom' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { getModuleDisplayName } from '@opentrons/shared-data' -import { RobotCoordsForeignObject } from '@opentrons/components' import * as wellContentsSelectors from '../../top-selectors/well-contents' -import { getAdditionalEquipmentEntities } from '../../step-forms/selectors' import { selectors } from '../../labware-ingred/selectors' import { selectors as uiLabwareSelectors } from '../../ui/labware' import { getDeckSetupForActiveItem } from '../../top-selectors/labware-locations' import { SlotInformation } from '../../organisms/SlotInformation' -import { getXPosition } from './utils' import type { DeckSlotId, RobotType } from '@opentrons/shared-data' import type { ContentsByWell } from '../../labware-ingred/types' -const SLOT_DETAIL_Y_POSITION = '-10' interface SlotDetailContainerProps { robotType: RobotType slot: DeckSlotId | null @@ -26,17 +21,12 @@ export function SlotDetailsContainer( ): JSX.Element | null { const { robotType, slot, offDeckLabwareId } = props const { t } = useTranslation('shared') - const location = useLocation() const deckSetup = useSelector(getDeckSetupForActiveItem) const allWellContentsForActiveItem = useSelector( wellContentsSelectors.getAllWellContentsForActiveItem ) const nickNames = useSelector(uiLabwareSelectors.getLabwareNicknamesById) const allIngredNamesIds = useSelector(selectors.allIngredientNamesIds) - const additionalEquipment = useSelector(getAdditionalEquipmentEntities) - const hasStagingArea = Object.values(additionalEquipment).some( - item => item.name === 'stagingArea' - ) if (slot == null || (slot === 'offDeck' && offDeckLabwareId == null)) { return null @@ -108,24 +98,7 @@ export function SlotDetailsContainer( } } - return location.pathname === '/designer' && slot !== 'offDeck' ? ( - - - - ) : ( + return ( { - if (robotType === FLEX_ROBOT_TYPE) { - if (FLEX_TOP_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.FLEX.TOP - } else if (FLEX_TOP_MIDDLE_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.FLEX.TOP_MIDDLE - } else if (FLEX_BOTTOM_MIDDLE_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.FLEX.BOTTOM_MIDDLE - } else { - return Y_POSITIONS.FLEX.BOTTOM - } - } else { - if (OT2_TOP_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.OT2.TOP - } else if (OT2_TOP_MIDDLE_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.OT2.TOP_MIDDLE - } else if (OT2_BOTTOM_MIDDLE_ROW_SLOTS.includes(slot)) { - return Y_POSITIONS.OT2.BOTTOM_MIDDLE - } else { - return Y_POSITIONS.OT2.BOTTOM - } - } -} - -export const getXPosition = ( - slot: string, - robotType: RobotType, - hasStagingArea: boolean -): string => { - const POSITION_MAP = { - FLEX: { - right: (slot: string) => (hasStagingArea ? '700' : '600'), - left: '-400', - regex: /[34]/, - }, - OT2: { - right: '420', - left: '-300', - regex: /[369]/, - }, - } - - const { right, left, regex } = - robotType === FLEX_ROBOT_TYPE ? POSITION_MAP.FLEX : POSITION_MAP.OT2 - - return regex.test(slot) - ? typeof right === 'function' - ? right(slot) - : right - : left -} diff --git a/protocol-designer/src/organisms/SlotInformation/index.tsx b/protocol-designer/src/organisms/SlotInformation/index.tsx index 1e6a29746f6..0ee7205fd97 100644 --- a/protocol-designer/src/organisms/SlotInformation/index.tsx +++ b/protocol-designer/src/organisms/SlotInformation/index.tsx @@ -12,8 +12,16 @@ import { StyledText, TYPOGRAPHY, } from '@opentrons/components' -import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' +import { + FLEX_ROBOT_TYPE, + getModuleDisplayName, + TC_MODULE_LOCATION_OT2, + TC_MODULE_LOCATION_OT3, + THERMOCYCLER_MODULE_V1, + THERMOCYCLER_MODULE_V2, +} from '@opentrons/shared-data' import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' +import { useDeckSetupWindowBreakPoint } from '../../pages/Designer/DeckSetup/utils' import type { FC } from 'react' import type { RobotType } from '@opentrons/shared-data' @@ -38,15 +46,28 @@ export const SlotInformation: FC = ({ fixtures = [], }) => { const { t } = useTranslation('shared') + const breakPointSize = useDeckSetupWindowBreakPoint() + const pathLocation = useLocation() const isOffDeck = location === 'offDeck' + const tcDisplayLocation = + robotType === FLEX_ROBOT_TYPE + ? TC_MODULE_LOCATION_OT3 + : TC_MODULE_LOCATION_OT2 + const modifiedLocation = + modules.includes(getModuleDisplayName(THERMOCYCLER_MODULE_V2)) || + modules.includes(getModuleDisplayName(THERMOCYCLER_MODULE_V1)) + ? tcDisplayLocation + : location + return ( - {isOffDeck ? null : } + {isOffDeck ? null : } {t(isOffDeck ? 'labware_detail' : 'slot_detail')} @@ -55,11 +76,16 @@ export const SlotInformation: FC = ({ {liquids.length > 1 ? ( {liquids.join(', ')} @@ -92,11 +118,10 @@ interface StackInfoListProps { } function StackInfoList({ title, items }: StackInfoListProps): JSX.Element { - const pathLocation = useLocation() return ( {items.length > 0 ? ( @@ -121,20 +146,27 @@ interface StackInfoProps { function StackInfo({ title, stackInformation }: StackInfoProps): JSX.Element { const { t } = useTranslation('shared') + const breakPointSize = useDeckSetupWindowBreakPoint() + return ( {stackInformation ?? t('none')} } description={ - + {title} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx index 2e45768cf4d..921e9c1fc55 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux' import { ALIGN_CENTER, BORDERS, + Box, COLORS, DIRECTION_COLUMN, DeckFromLayers, @@ -37,6 +38,7 @@ import { DeckSetupDetails } from './DeckSetupDetails' import { animateZoom, getCutoutIdForAddressableArea, + useDeckSetupWindowBreakPoint, zoomInOnCoordinate, } from './utils' import { DeckSetupTools } from './DeckSetupTools' @@ -68,11 +70,30 @@ const OT2_STANDARD_DECK_VIEW_LAYER_BLOCK_LIST: string[] = [ ] export const lightFill = COLORS.grey35 export const darkFill = COLORS.grey60 +const LEFT_SLOTS = [ + 'A1', + 'A2', + 'B1', + 'B2', + 'C1', + 'C2', + 'D1', + 'D2', + '1', + '2', + '4', + '5', + '7', + '8', + '10', + '11', +] export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { const { tab } = props const activeDeckSetup = useSelector(getDeckSetupForActiveItem) const dispatch = useDispatch() + const breakPointSize = useDeckSetupWindowBreakPoint() const zoomIn = useSelector(selectors.getZoomedInSlot) const _disableCollisionWarnings = useSelector(getDisableModuleRestrictions) const robotType = useSelector(getRobotType) @@ -97,6 +118,7 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { aE.location === WASTE_CHUTE_CUTOUT && wasteChuteFixtures.length > 0 ) + const hasWasteChute = wasteChuteFixtures.length > 0 || wasteChuteStagingAreaFixtures.length > 0 @@ -112,6 +134,7 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { const initialViewBox = `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}` const [viewBox, setViewBox] = useState(initialViewBox) + const [hoveredLabware, setHoveredLabware] = useState(null) const [hoveredModule, setHoveredModule] = useState(null) const [hoveredFixture, setHoveredFixture] = useState(null) @@ -179,7 +202,7 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { width="100%" height={zoomIn.slot != null ? '75vh' : '70vh'} flexDirection={DIRECTION_COLUMN} - padding={SPACING.spacing40} + padding={SPACING.spacing24} maxHeight="39.375rem" // this is to block deck view from enlarging > + + {hoverSlot != null && + breakPointSize !== 'small' && + LEFT_SLOTS.includes(hoverSlot) ? ( + + ) : null} + 0} /> - {hoverSlot != null ? ( - - ) : null} )} + + {hoverSlot != null && + breakPointSize !== 'small' && + !LEFT_SLOTS.includes(hoverSlot) ? ( + + ) : null} + {zoomIn.slot != null && zoomIn.cutout != null ? ( diff --git a/protocol-designer/src/pages/Designer/DeckSetup/SlotOverflowMenu.tsx b/protocol-designer/src/pages/Designer/DeckSetup/SlotOverflowMenu.tsx index b29d3b90dfa..36cd92f4ec6 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/SlotOverflowMenu.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/SlotOverflowMenu.tsx @@ -61,7 +61,7 @@ const BOTTOM_SLOT_Y_POSITION = -70 const TOP_SLOT_Y_POSITION = 50 const TOP_SLOT_Y_POSITION_ALL_BUTTONS = 110 const TOP_SLOT_Y_POSITION_2_BUTTONS = 35 - +const STAGING_AREA_SLOTS = ['A4', 'B4', 'C4', 'D4'] interface SlotOverflowMenuProps { // can be off-deck id or deck slot location: DeckSlotId | string @@ -317,7 +317,10 @@ export function SlotOverflowMenu( return menuListSlotPosition != null ? ( { + const handleResize = (): void => { + setWindowSize({ + width: window.innerWidth, + height: window.innerHeight, + }) + } + + window.addEventListener('resize', handleResize) + + return () => { + window.removeEventListener('resize', handleResize) + } + }, []) + + let size: BreakPoint = 'large' + if (windowSize.width <= 1024 && windowSize.width > 800) { + size = 'medium' + } else if (windowSize.width <= 800) { + size = 'small' + } + + return size +} diff --git a/protocol-designer/src/pages/Designer/index.tsx b/protocol-designer/src/pages/Designer/index.tsx index a1ec3a27e4a..3469a843eb4 100644 --- a/protocol-designer/src/pages/Designer/index.tsx +++ b/protocol-designer/src/pages/Designer/index.tsx @@ -165,7 +165,7 @@ export function Designer(): JSX.Element {