From ce8265cf438827dfe6fc183a505a2b3bd37ed955 Mon Sep 17 00:00:00 2001 From: koji Date: Thu, 31 Oct 2024 15:35:23 -0400 Subject: [PATCH] fix(protocol-designer): Fix deck view size issues in pd (#16616) * fix(protocol-designer): Fix deck view size issues in pd --- .../RobotCoordinateSpaceWithRef.tsx | 28 +++++++--- protocol-designer/src/atoms/constants.ts | 1 + .../AssignLiquidsModal/LiquidCard.tsx | 13 ++++- .../__tests__/utils.test.ts | 21 ++++++++ .../organisms/DefineLiquidsModal/index.tsx | 6 ++- .../__tests__/utils.test.ts | 25 +++++++++ .../organisms/SlotDetailsContainer/index.tsx | 12 +++-- .../organisms/SlotDetailsContainer/utils.ts | 28 ++++++++++ .../src/organisms/SlotInformation/index.tsx | 12 ++++- .../Designer/DeckSetup/DeckSetupContainer.tsx | 5 +- .../pages/Designer/LiquidsOverflowMenu.tsx | 54 ++++++++++--------- .../StepForm/StepFormToolbox.tsx | 5 +- .../ProtocolSteps/Timeline/StepContainer.tsx | 5 +- .../src/pages/Designer/index.tsx | 2 +- .../pages/ProtocolOverview/DeckThumbnail.tsx | 21 +++++--- 15 files changed, 181 insertions(+), 57 deletions(-) create mode 100644 protocol-designer/src/organisms/DefineLiquidsModal/__tests__/utils.test.ts create mode 100644 protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts diff --git a/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx b/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx index c1986711ed2..530ed004532 100644 --- a/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx +++ b/components/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx @@ -1,5 +1,7 @@ -import * as React from 'react' +import { useRef } from 'react' import { Svg } from '../../primitives' + +import type { ReactNode } from 'react' import type { DeckDefinition, DeckSlot } from '@opentrons/shared-data' export interface RobotCoordinateSpaceWithRefRenderProps { @@ -10,14 +12,15 @@ interface RobotCoordinateSpaceWithRefProps extends React.ComponentProps { viewBox?: string | null deckDef?: DeckDefinition - children?: (props: RobotCoordinateSpaceWithRefRenderProps) => React.ReactNode + zoomed?: boolean + children?: (props: RobotCoordinateSpaceWithRefRenderProps) => ReactNode } export function RobotCoordinateSpaceWithRef( props: RobotCoordinateSpaceWithRefProps ): JSX.Element | null { - const { children, deckDef, viewBox, ...restProps } = props - const wrapperRef = React.useRef(null) + const { children, deckDef, viewBox, zoomed = false, ...restProps } = props + const wrapperRef = useRef(null) if (deckDef == null && viewBox == null) return null @@ -31,13 +34,26 @@ export function RobotCoordinateSpaceWithRef( (acc, deckSlot) => ({ ...acc, [deckSlot.id]: deckSlot }), {} ) - wholeDeckViewBox = `${viewBoxOriginX} ${viewBoxOriginY} ${deckXDimension} ${deckYDimension}` + + if (deckDef.otId === 'ot2_standard') { + const PADDING = 5 + wholeDeckViewBox = `${viewBoxOriginX - PADDING} ${ + viewBoxOriginY + PADDING * 5 + } ${deckXDimension + PADDING * 2} ${deckYDimension - PADDING * 10}` + } else { + const PADDING = 20 + wholeDeckViewBox = `${viewBoxOriginX - PADDING} ${ + viewBoxOriginY + PADDING + } ${deckXDimension + PADDING * 2} ${deckYDimension + PADDING * 2}` + } } return ( {children?.({ deckSlotsById })} diff --git a/protocol-designer/src/atoms/constants.ts b/protocol-designer/src/atoms/constants.ts index e1acf21fddc..6e357feaf3a 100644 --- a/protocol-designer/src/atoms/constants.ts +++ b/protocol-designer/src/atoms/constants.ts @@ -18,4 +18,5 @@ export const LINE_CLAMP_TEXT_STYLE = ( text-overflow: ellipsis; word-wrap: break-word; -webkit-line-clamp: ${lineClamp}; + word-break: break-all; // for a non word case like aaaaaaaa ` diff --git a/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx b/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx index d1680010e2d..54ad8b67b66 100644 --- a/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx +++ b/protocol-designer/src/organisms/AssignLiquidsModal/LiquidCard.tsx @@ -18,6 +18,7 @@ import { import { selectors as labwareIngredSelectors } from '../../labware-ingred/selectors' import { getLabwareEntities } from '../../step-forms/selectors' import * as wellContentsSelectors from '../../top-selectors/well-contents' +import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' import type { LiquidInfo } from './LiquidToolbox' @@ -80,8 +81,16 @@ export function LiquidCard(props: LiquidCardProps): JSX.Element { > - {name} - + + {name} + + {info.liquidIndex != null ? liquidsWithDescriptions[info.liquidIndex].description : null} diff --git a/protocol-designer/src/organisms/DefineLiquidsModal/__tests__/utils.test.ts b/protocol-designer/src/organisms/DefineLiquidsModal/__tests__/utils.test.ts new file mode 100644 index 00000000000..4e1016039b9 --- /dev/null +++ b/protocol-designer/src/organisms/DefineLiquidsModal/__tests__/utils.test.ts @@ -0,0 +1,21 @@ +import { describe, it, expect } from 'vitest' +import { checkColor } from '../utils' + +describe('checkColor', () => { + it('should return true for very dark colors', () => { + expect(checkColor('#000000')).toBe(true) + expect(checkColor('#0a0a0a')).toBe(true) + }) + + it('should return true for very light colors', () => { + expect(checkColor('#ffffff')).toBe(true) + expect(checkColor('#f5f5f5')).toBe(true) + }) + + it('should return false for colors with medium luminance', () => { + expect(checkColor('#808080')).toBe(false) + expect(checkColor('#ff0000')).toBe(false) + expect(checkColor('#00ff00')).toBe(false) + expect(checkColor('#0000ff')).toBe(false) + }) +}) diff --git a/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx b/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx index e9943676c35..ae30ab973a2 100644 --- a/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx +++ b/protocol-designer/src/organisms/DefineLiquidsModal/index.tsx @@ -34,6 +34,7 @@ import { selectors as labwareIngredSelectors } from '../../labware-ingred/select import { swatchColors } from '../../components/swatchColors' import { checkColor } from './utils' import { HandleEnter } from '../../atoms/HandleEnter' +import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' import type { ColorResult, RGBColor } from 'react-color' import type { ThunkDispatch } from 'redux-thunk' @@ -173,7 +174,10 @@ export function DefineLiquidsModal( selectedIngredFields != null ? ( - + {initialValues.name} diff --git a/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts b/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts new file mode 100644 index 00000000000..eef8e3153c2 --- /dev/null +++ b/protocol-designer/src/organisms/SlotDetailsContainer/__tests__/utils.test.ts @@ -0,0 +1,25 @@ +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 7e2d215cd31..b0b408a4964 100644 --- a/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx +++ b/protocol-designer/src/organisms/SlotDetailsContainer/index.tsx @@ -4,15 +4,17 @@ 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 { getYPosition } from './utils' +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 @@ -31,6 +33,10 @@ export function SlotDetailsContainer( ) 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 @@ -106,8 +112,8 @@ export function SlotDetailsContainer( { } } } + +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 4e7d2ffbfd6..85e9a1ef636 100644 --- a/protocol-designer/src/organisms/SlotInformation/index.tsx +++ b/protocol-designer/src/organisms/SlotInformation/index.tsx @@ -12,6 +12,8 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' +import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' + import type { FC } from 'react' import type { RobotType } from '@opentrons/shared-data' @@ -53,7 +55,15 @@ export const SlotInformation: FC = ({ {liquids.join(', ')}} + content={ + + {liquids.join(', ')} + + } description={t('liquid')} /> diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx index 20ad1307919..b06cbfd535a 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx @@ -176,7 +176,7 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { backgroundColor={COLORS.white} borderRadius={BORDERS.borderRadius12} width="100%" - height={zoomIn.slot != null ? '75vh' : '65vh'} + height={zoomIn.slot != null ? '75vh' : '70vh'} flexDirection={DIRECTION_COLUMN} padding={SPACING.spacing40} > @@ -187,11 +187,12 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { justifyContent={JUSTIFY_CENTER} > {() => ( <> diff --git a/protocol-designer/src/pages/Designer/LiquidsOverflowMenu.tsx b/protocol-designer/src/pages/Designer/LiquidsOverflowMenu.tsx index 582232e00ef..2e0b6a8a02f 100644 --- a/protocol-designer/src/pages/Designer/LiquidsOverflowMenu.tsx +++ b/protocol-designer/src/pages/Designer/LiquidsOverflowMenu.tsx @@ -1,5 +1,4 @@ -import type * as React from 'react' -import styled from 'styled-components' +import { css } from 'styled-components' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { useLocation } from 'react-router-dom' @@ -8,19 +7,22 @@ import { BORDERS, Box, COLORS, - CURSOR_AUTO, CURSOR_POINTER, DIRECTION_COLUMN, Flex, Icon, LiquidIcon, - NO_WRAP, + MenuItem, POSITION_ABSOLUTE, SPACING, StyledText, + TYPOGRAPHY, } from '@opentrons/components' +import { LINE_CLAMP_TEXT_STYLE } from '../../atoms' import { selectors as labwareIngredSelectors } from '../../labware-ingred/selectors' import * as labwareIngredActions from '../../labware-ingred/actions' + +import type { MouseEvent } from 'react' import type { ThunkDispatch } from '../../types' const NAV_HEIGHT = '64px' @@ -46,20 +48,20 @@ export function LiquidsOverflowMenu( zIndex={5} right={location.pathname === '/liquids' ? SPACING.spacing12 : '3.125rem'} top={`calc(${NAV_HEIGHT} - 6px)`} - whiteSpace={NO_WRAP} ref={overflowWrapperRef} borderRadius={BORDERS.borderRadius8} boxShadow="0px 1px 3px rgba(0, 0, 0, 0.2)" backgroundColor={COLORS.white} flexDirection={DIRECTION_COLUMN} - onClick={(e: React.MouseEvent) => { + onClick={(e: MouseEvent) => { e.preventDefault() e.stopPropagation() }} + width="9.375rem" > {liquids.map(({ name, displayColor, ingredientId }) => { return ( - { onClose() @@ -67,18 +69,29 @@ export function LiquidsOverflowMenu( dispatch(labwareIngredActions.selectLiquidGroup(ingredientId)) }} key={ingredientId} + css={css` + cursor: ${CURSOR_POINTER}; + `} > - {name} + + {name} + - + ) })} {liquids.length > 0 ? ( ) : null} - { onClose() @@ -86,28 +99,17 @@ export function LiquidsOverflowMenu( dispatch(labwareIngredActions.createNewLiquidGroup()) }} key="defineLiquid" + css={css` + cursor: ${CURSOR_POINTER}; + `} > - + {t('define_liquid')} - + ) } -const MenuButton = styled.button` - background-color: ${COLORS.transparent}; - cursor: ${CURSOR_POINTER}; - padding: ${SPACING.spacing8} ${SPACING.spacing12}; - border: none; - border-radius: inherit; - &:hover { - background-color: ${COLORS.blue10}; - } - &:disabled { - color: ${COLORS.grey40}; - cursor: ${CURSOR_AUTO}; - } -` diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 634bb422ecb..a14be039d93 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx @@ -234,10 +234,7 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { {capitalizeFirstLetter(String(formData.stepName))} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx index c869fdf72dd..d6f5b532e79 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx @@ -227,10 +227,7 @@ export function StepContainer(props: StepContainerProps): JSX.Element { )} {capitalizeFirstLetterAfterNumber(title)} diff --git a/protocol-designer/src/pages/Designer/index.tsx b/protocol-designer/src/pages/Designer/index.tsx index 84b1f7f20d8..85597ba3e66 100644 --- a/protocol-designer/src/pages/Designer/index.tsx +++ b/protocol-designer/src/pages/Designer/index.tsx @@ -202,7 +202,7 @@ export function Designer(): JSX.Element { padding={zoomIn.slot != null ? '0' : SPACING.spacing80} height="calc(100vh - 64px)" > - + {zoomIn.slot == null ? ( > + setHoverSlot: Dispatch> } export function DeckThumbnail(props: DeckThumbnailProps): JSX.Element { const { hoverSlot, setHoverSlot } = props const initialDeckSetup = useSelector(getInitialDeckSetup) const robotType = useSelector(getRobotType) - const deckDef = React.useMemo(() => getDeckDefFromRobotType(robotType), []) + const deckDef = useMemo(() => getDeckDefFromRobotType(robotType), []) const trash = Object.values(initialDeckSetup.additionalEquipmentOnDeck).find( ae => ae.name === 'trashBin' ) @@ -99,11 +103,14 @@ export function DeckThumbnail(props: DeckThumbnailProps): JSX.Element { width="100%" alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_CENTER} - backgroundColor={COLORS.grey10} + backgroundColor={ + robotType === OT2_ROBOT_TYPE ? COLORS.white : COLORS.grey10 + } + paddingY={robotType === FLEX_ROBOT_TYPE && SPACING.spacing24} borderRadius={BORDERS.borderRadius8} > cutoutId != null ? ( - + - + ) : null ) : null}