From 8430cd1e25a0af6bad72895f1778c06ad21fc755 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:21:31 -0400 Subject: [PATCH] fix(app, components): fix labware map view selection ODD (#15930) Render proper modal depending on if labware is top element of stack or loaded directly on deck. Refactors to use the same state variable to keep track of the selected labware, and determines which modal to show depending on if the selected labware was loaded onto a module/adapter or directly onto the deck. --- .../SetupLabware/LabwareStackModal.tsx | 31 ++++++++++++-- .../SetupLabware/SetupLabwareMap.tsx | 1 + .../organisms/ProtocolSetupLabware/index.tsx | 41 +++++++------------ .../Labware/LabwareStackRender.tsx | 7 ++-- 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareStackModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareStackModal.tsx index 83fdf1d9260..80bd38a3255 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareStackModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareStackModal.tsx @@ -23,9 +23,17 @@ import { getLocationInfoNames } from '../utils/getLocationInfoNames' import { getSlotLabwareDefinition } from '../utils/getSlotLabwareDefinition' import { Divider } from '../../../../atoms/structure' import { getModuleImage } from '../SetupModuleAndDeck/utils' -import { getModuleDisplayName } from '@opentrons/shared-data' +import { + FLEX_ROBOT_TYPE, + getModuleDisplayName, + getModuleType, + TC_MODULE_LOCATION_OT2, + TC_MODULE_LOCATION_OT3, +} from '@opentrons/shared-data' import tiprackAdapter from '../../../../assets/images/labware/opentrons_flex_96_tiprack_adapter.png' +import type { RobotType } from '@opentrons/shared-data' + const HIDE_SCROLLBAR = css` ::-webkit-scrollbar { display: none; @@ -36,12 +44,13 @@ interface LabwareStackModalProps { labwareIdTop: string runId: string closeModal: () => void + robotType?: RobotType } export const LabwareStackModal = ( props: LabwareStackModalProps ): JSX.Element | null => { - const { labwareIdTop, runId, closeModal } = props + const { labwareIdTop, runId, closeModal, robotType = FLEX_ROBOT_TYPE } = props const { t } = useTranslation('protocol_setup') const isOnDevice = useSelector(getIsOnDevice) const protocolData = useMostRecentCompletedAnalysis(runId) @@ -60,6 +69,14 @@ export const LabwareStackModal = ( const topDefinition = getSlotLabwareDefinition(labwareIdTop, commands) const adapterDef = getSlotLabwareDefinition(adapterId ?? '', commands) + const isModuleThermocycler = + moduleModel == null + ? false + : getModuleType(moduleModel) === 'thermocyclerModuleType' + const thermocyclerLocation = + robotType === FLEX_ROBOT_TYPE + ? TC_MODULE_LOCATION_OT3 + : TC_MODULE_LOCATION_OT2 const moduleDisplayName = moduleModel != null ? getModuleDisplayName(moduleModel) : null ?? '' const tiprackAdapterImg = ( @@ -80,7 +97,9 @@ export const LabwareStackModal = ( header={{ title: ( <Flex gridGap={SPACING.spacing4}> - <DeckInfoLabel deckLabel={slotName} /> + <DeckInfoLabel + deckLabel={isModuleThermocycler ? thermocyclerLocation : slotName} + /> <DeckInfoLabel iconName="stacked" /> </Flex> ), @@ -156,7 +175,11 @@ export const LabwareStackModal = ( onClose={closeModal} closeOnOutsideClick title={t('stacked_slot')} - titleElement1={<DeckInfoLabel deckLabel={slotName} />} + titleElement1={ + <DeckInfoLabel + deckLabel={isModuleThermocycler ? thermocyclerLocation : slotName} + /> + } titleElement2={<DeckInfoLabel iconName="stacked" />} childrenPadding={0} marginLeft="0" diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx index 9a3c04fdc5f..8a35d8d203e 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx @@ -180,6 +180,7 @@ export function SetupLabwareMap({ closeModal={() => { setLabwareStackDetailsLabwareId(null) }} + robotType={robotType} /> )} </Flex> diff --git a/app/src/organisms/ProtocolSetupLabware/index.tsx b/app/src/organisms/ProtocolSetupLabware/index.tsx index 919d887f491..cbc8d363b4b 100644 --- a/app/src/organisms/ProtocolSetupLabware/index.tsx +++ b/app/src/organisms/ProtocolSetupLabware/index.tsx @@ -98,6 +98,7 @@ export function ProtocolSetupLabware({ | (LabwareDefinition2 & { location: LabwareLocation nickName: string | null + id: string }) | null >(null) @@ -143,13 +144,21 @@ export function ProtocolSetupLabware({ ...labwareDef, location: foundLabware.location, nickName: nickName ?? null, + id: labwareId, }) setShowLabwareDetailsModal(true) } } + const selectedLabwareIsTopOfStack = mostRecentAnalysis?.commands.some( + command => + command.commandType === 'loadLabware' && + command.result?.labwareId === selectedLabware?.id && + typeof command.params.location === 'object' && + ('moduleId' in command.params.location || + 'labwareId' in command.params.location) + ) let location: JSX.Element | string | null = null - let topLabwareId: string | null = null if ( selectedLabware != null && typeof selectedLabware.location === 'object' && @@ -178,17 +187,6 @@ export function ProtocolSetupLabware({ module.moduleId === selectedLabware.location.moduleId ) if (matchedModule != null) { - topLabwareId = - mostRecentAnalysis?.commands.find( - (command): command is LoadLabwareRunTimeCommand => { - return ( - command.commandType === 'loadLabware' && - typeof command.params.location === 'object' && - 'moduleId' in command.params.location && - command.params.location.moduleId === matchedModule.moduleId - ) - } - )?.result?.labwareId ?? null location = <DeckInfoLabel deckLabel={matchedModule?.slotName} /> } } else if ( @@ -203,17 +201,6 @@ export function ProtocolSetupLabware({ command.result?.labwareId === adapterId )?.params.location if (adapterLocation != null && adapterLocation !== 'offDeck') { - topLabwareId = - mostRecentAnalysis?.commands.find( - (command): command is LoadLabwareRunTimeCommand => { - return ( - command.commandType === 'loadLabware' && - typeof command.params.location === 'object' && - 'labwareId' in command.params.location && - command.params.location.labwareId === adapterId - ) - } - )?.result?.labwareId ?? null if ('slotName' in adapterLocation) { location = <DeckInfoLabel deckLabel={adapterLocation.slotName} /> } else if ('moduleId' in adapterLocation) { @@ -232,7 +219,7 @@ export function ProtocolSetupLabware({ {createPortal( <> {showLabwareDetailsModal && - topLabwareId == null && + !selectedLabwareIsTopOfStack && selectedLabware != null ? ( <Modal onOutsideClick={() => { @@ -357,9 +344,11 @@ export function ProtocolSetupLabware({ })} </> )} - {showLabwareDetailsModal && topLabwareId != null ? ( + {showLabwareDetailsModal && + selectedLabware != null && + selectedLabwareIsTopOfStack ? ( <LabwareStackModal - labwareIdTop={topLabwareId} + labwareIdTop={selectedLabware?.id} runId={runId} closeModal={() => { setSelectedLabware(null) diff --git a/components/src/hardware-sim/Labware/LabwareStackRender.tsx b/components/src/hardware-sim/Labware/LabwareStackRender.tsx index d9184e327f0..6b1b9aec35d 100644 --- a/components/src/hardware-sim/Labware/LabwareStackRender.tsx +++ b/components/src/hardware-sim/Labware/LabwareStackRender.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { WellLabels, StaticLabware } from './labwareInternals' -import { LabwareAdapter } from './LabwareAdapter' +import { LabwareAdapter, labwareAdapterLoadNames } from './LabwareAdapter' import { COLORS } from '../../helix-design-system' import { Svg } from '../..' @@ -8,7 +8,6 @@ import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { HighlightedWellLabels } from './labwareInternals/types' import type { LabwareAdapterLoadName } from './LabwareAdapter' import type { WellLabelOption } from '../..' - const HIGHLIGHT_COLOR = COLORS.blue30 const STROKE_WIDTH = 1 const SKEW_ANGLE_DEGREES = 30 @@ -87,7 +86,9 @@ export const LabwareStackRender = ( definitionBottom.parameters.loadName === 'opentrons_flex_96_tiprack_adapter' ) { const { xDimension, yDimension } = definitionTop.dimensions - const isTopAdapter = definitionTop.metadata.displayCategory === 'adapter' + const isTopAdapter = labwareAdapterLoadNames.includes( + definitionTop.parameters.loadName + ) return isTopAdapter ? ( // adapter render