From 57a8152a1abaa0fc3ecce4153d6aa90fd963e5a4 Mon Sep 17 00:00:00 2001
From: Jethary Rader <66035149+jerader@users.noreply.github.com>
Date: Tue, 9 Apr 2024 17:41:18 -0400
Subject: [PATCH] =?UTF-8?q?refactor(protocol-designer,=20components):=20in?=
=?UTF-8?q?foItem=20to=20nicely=20accommoda=E2=80=A6=20(#14850)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
…te multiple tipracks
closes AUTH-314
---
components/src/instrument/InfoItem.tsx | 24 ----
components/src/instrument/InstrumentInfo.tsx | 110 +++++++++++-------
.../__tests__/InstrumentInfo.test.tsx | 54 +++++++++
components/src/instrument/index.ts | 1 -
.../src/step-forms/selectors/index.ts | 1 -
5 files changed, 122 insertions(+), 68 deletions(-)
delete mode 100644 components/src/instrument/InfoItem.tsx
create mode 100644 components/src/instrument/__tests__/InstrumentInfo.test.tsx
diff --git a/components/src/instrument/InfoItem.tsx b/components/src/instrument/InfoItem.tsx
deleted file mode 100644
index 82b5a491a37..00000000000
--- a/components/src/instrument/InfoItem.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import * as React from 'react'
-
-import styles from './instrument.module.css'
-
-export interface InfoItemProps {
- title: string | null
- value: string
- className?: string
-}
-
-/**
- * Used by `InstrumentInfo` for its titled values.
- * But if you're using this, you probably want `LabeledValue` instead.
- */
-export function InfoItem(props: InfoItemProps): JSX.Element {
- const { title, value, className } = props
-
- return (
-
- {title != null ?
{title}
: null}
- {value}
-
- )
-}
diff --git a/components/src/instrument/InstrumentInfo.tsx b/components/src/instrument/InstrumentInfo.tsx
index d5d26a3b4b4..57ff12e0ed4 100644
--- a/components/src/instrument/InstrumentInfo.tsx
+++ b/components/src/instrument/InstrumentInfo.tsx
@@ -1,77 +1,103 @@
import * as React from 'react'
import { LEFT, RIGHT } from '@opentrons/shared-data'
-import { InfoItem } from './InfoItem'
-import { InstrumentDiagram } from './InstrumentDiagram'
-import styles from './instrument.module.css'
import { Flex } from '../primitives'
-import { SPACING } from '../ui-style-constants'
+import { SPACING, TYPOGRAPHY } from '../ui-style-constants'
+import { StyledText } from '../atoms'
import { DIRECTION_COLUMN, JUSTIFY_CENTER } from '../styles'
+import { InstrumentDiagram } from './InstrumentDiagram'
import type { Mount } from '../robot-types'
import type { InstrumentDiagramProps } from './InstrumentDiagram'
+import styles from './instrument.module.css'
+
export interface InstrumentInfoProps {
/** 'left' or 'right' */
mount: Mount
- /** if true, show labels 'LEFT PIPETTE' / 'RIGHT PIPETTE' */
- showMountLabel?: boolean | null
/** human-readable description, eg 'p300 Single-channel' */
description: string
- /** paired tiprack models */
- tiprackModels?: string[]
- /** if disabled, pipette & its info are grayed out */
- isDisabled: boolean
/** specs of mounted pipette */
pipetteSpecs?: InstrumentDiagramProps['pipetteSpecs'] | null
- /** classes to apply */
- className?: string
- /** classes to apply to the info group child */
- infoClassName?: string
+ /** paired tiprack models */
+ tiprackModels?: string[]
/** children to display under the info */
children?: React.ReactNode
+ /** if true, show labels 'LEFT PIPETTE' / 'RIGHT PIPETTE' */
+ showMountLabel?: boolean | null
}
+const MAX_WIDTH = '14rem'
+
export function InstrumentInfo(props: InstrumentInfoProps): JSX.Element {
- const has96Channel = props.pipetteSpecs?.channels === 96
+ const {
+ mount,
+ showMountLabel,
+ description,
+ tiprackModels,
+ pipetteSpecs,
+ children,
+ } = props
+
+ const has96Channel = pipetteSpecs?.channels === 96
return (
- {props.mount === RIGHT && props.pipetteSpecs && (
+ {mount === RIGHT && pipetteSpecs ? (
- )}
+ ) : null}
+ {/* NOTE: the color is our legacy c-font-dark, which matches the other colors in this component **/}
+
+
+
+ {showMountLabel && !has96Channel ? `${mount} pipette` : 'pipette'}
+
+
+ {description}
+
+
-
-
- {props.tiprackModels != null
- ? props.tiprackModels.map((model, index) => (
-
- ))
- : null}
+
+
+ {'Tip rack'}
+
+
+ {tiprackModels != null && tiprackModels.length > 0 ? (
+ tiprackModels.map((model, index) => (
+ -
+
+ {model}
+
+
+ ))
+ ) : (
+
+ {'None'}
+
+ )}
+
+
- {props.children}
- {props.mount === LEFT && props.pipetteSpecs && (
+ {children}
+ {mount === LEFT && pipetteSpecs ? (
- )}
+ ) : null}
)
}
diff --git a/components/src/instrument/__tests__/InstrumentInfo.test.tsx b/components/src/instrument/__tests__/InstrumentInfo.test.tsx
new file mode 100644
index 00000000000..bf92c48d4cb
--- /dev/null
+++ b/components/src/instrument/__tests__/InstrumentInfo.test.tsx
@@ -0,0 +1,54 @@
+import * as React from 'react'
+import { screen } from '@testing-library/react'
+import { describe, beforeEach, it, vi } from 'vitest'
+import { LEFT, RIGHT, fixtureP1000SingleV2Specs } from '@opentrons/shared-data'
+import { renderWithProviders } from '../../testing/utils'
+import { InstrumentInfo } from '../InstrumentInfo'
+import { InstrumentDiagram } from '../InstrumentDiagram'
+
+vi.mock('../InstrumentDiagram')
+const render = (props: React.ComponentProps) => {
+ return renderWithProviders()[0]
+}
+
+describe('InstrumentInfo', () => {
+ let props: React.ComponentProps
+
+ beforeEach(() => {
+ props = {
+ mount: LEFT,
+ description: 'mock description',
+ pipetteSpecs: fixtureP1000SingleV2Specs,
+ tiprackModels: ['mock1', 'mock2'],
+ showMountLabel: true,
+ }
+ vi.mocked(InstrumentDiagram).mockReturnValue(
+ mock instrumentDiagram
+ )
+ })
+ it('renders a p1000 pipette with 2 tiprack models for left mount', () => {
+ render(props)
+ screen.getByText('mock instrumentDiagram')
+ screen.getByText('left pipette')
+ screen.getByText('mock description')
+ screen.getByText('Tip rack')
+ screen.getByText('mock1')
+ screen.getByText('mock2')
+ })
+ it('renders a p1000 pipette with 1 tiprack model for right mount', () => {
+ props.mount = RIGHT
+ props.tiprackModels = ['mock1']
+ render(props)
+ screen.getByText('mock instrumentDiagram')
+ screen.getByText('right pipette')
+ screen.getByText('mock description')
+ screen.getByText('Tip rack')
+ screen.getByText('mock1')
+ })
+ it('renders none for pip and tiprack if none are selected', () => {
+ props.pipetteSpecs = undefined
+ props.tiprackModels = undefined
+ render(props)
+ screen.getByText('None')
+ })
+})
diff --git a/components/src/instrument/index.ts b/components/src/instrument/index.ts
index 1153df43ae7..d566fb66e5b 100644
--- a/components/src/instrument/index.ts
+++ b/components/src/instrument/index.ts
@@ -1,4 +1,3 @@
-export * from './InfoItem'
export * from './InstrumentDiagram'
export * from './InstrumentGroup'
export * from './InstrumentInfo'
diff --git a/protocol-designer/src/step-forms/selectors/index.ts b/protocol-designer/src/step-forms/selectors/index.ts
index a81846be991..1c0be8ca60c 100644
--- a/protocol-designer/src/step-forms/selectors/index.ts
+++ b/protocol-designer/src/step-forms/selectors/index.ts
@@ -406,7 +406,6 @@ export const getPipettesForInstrumentGroup: Selector<
mount: pipetteOnDeck.mount,
pipetteSpecs: pipetteSpec,
description: _getPipetteDisplayName(pipetteOnDeck.name),
- isDisabled: false,
tiprackModels: tiprackDefs?.map((def: LabwareDefinition2) =>
getLabwareDisplayName(def)
),