Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(app): add and use deck map component in interventionmodal #15570

Merged
merged 9 commits into from
Jul 5, 2024
Prev Previous commit
Next Next commit
refactor: use deckmap in error recovery
Two places in error recovery, refactoring as we go.

One big change was that there was a bunch of stuff called RecoveryMap as
in recovery (deck) map, but recovery also has the Recovery Map, the big
data structure that holds how all the steps of error recovery flow
together. This is very confusing, so now what used to be
RecoveryMap (component, utils) is now DeckMap.
  • Loading branch information
sfoster1 committed Jul 5, 2024
commit f11485d6bf79659f44521c3105eeaa5e1f4ea885
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import {
RecoveryFooterButtons,
RecoverySingleColumnContent,
LeftColumnLabwareInfo,
RecoveryMap,
TwoColTextAndFailedStepNextStep,
} from '../shared'
import { TwoColumn } from '../../../molecules/InterventionModal'
import { TwoColumn, DeckMapContent } from '../../../molecules/InterventionModal'
import { SelectRecoveryOption } from './SelectRecoveryOption'

import type { RecoveryContentProps } from '../types'
Expand Down Expand Up @@ -45,7 +44,12 @@ export function FillWellAndSkip(props: RecoveryContentProps): JSX.Element {
}

export function FillWell(props: RecoveryContentProps): JSX.Element | null {
const { isOnDevice, routeUpdateActions, failedLabwareUtils } = props
const {
isOnDevice,
routeUpdateActions,
failedLabwareUtils,
deckMapUtils,
} = props
const { t } = useTranslation('error_recovery')
const { goBackPrevStep, proceedNextStep } = routeUpdateActions

Expand All @@ -63,7 +67,7 @@ export function FillWell(props: RecoveryContentProps): JSX.Element | null {
/>
</Flex>
<Flex marginTop="1.742rem">
<RecoveryMap {...props} />
<DeckMapContent {...deckMapUtils} />
</Flex>
</TwoColumn>
<RecoveryFooterButtons
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const mockRecoveryContentProps: RecoveryContentProps = {
currentRecoveryOptionUtils: {} as any,
failedLabwareUtils: { pickUpTipLabware: mockPickUpTipLabware } as any,
failedPipetteInfo: {} as any,
recoveryMapUtils: {} as any,
deckMapUtils: {} as any,
stepCounts: {} as any,
protocolAnalysis: { commands: [mockFailedCommand] } as any,
trackExternalMap: () => null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as React from 'react'
import { describe, it, expect, beforeEach, vi } from 'vitest'

import {
Expand All @@ -17,8 +16,7 @@ import {
getRunCurrentModulesInfo,
getRunCurrentLabwareOnDeck,
getRunCurrentModulesOnDeck,
} from '../useRecoveryMapUtils'
import { LabwareHighlight } from '../../shared'
} from '../useDeckMapUtils'

import type { LabwareDefinition2 } from '@opentrons/shared-data'

Expand Down Expand Up @@ -78,13 +76,11 @@ describe('getRunCurrentModulesOnDeck', () => {
moduleLocation: { slotName: 'A1' },
innerProps: {},
nestedLabwareDef: mockLabwareDef,
moduleChildren: (
<LabwareHighlight highlight={true} definition={mockLabwareDef} />
),
highlight: 'MOCK_MODULE_ID',
},
])
})
it('should set moduleChildren to null if getIsLabwareMatch returns false', () => {
it('should set highlight to null if getIsLabwareMatch returns false', () => {
const result = getRunCurrentModulesOnDeck({
failedLabwareUtils: mockFailedLabwareUtils,
currentModulesInfo: [
Expand All @@ -95,18 +91,18 @@ describe('getRunCurrentModulesOnDeck', () => {
],
})

expect(result[0].moduleChildren).toBeNull()
expect(result[0].highlight).toBeNull()
})

it('should set moduleChildren to null if nestedLabwareDef is null', () => {
it('should set highlight to null if nestedLabwareDef is null', () => {
const result = getRunCurrentModulesOnDeck({
failedLabwareUtils: mockFailedLabwareUtils,
currentModulesInfo: [
{ ...mockCurrentModulesInfo[0], nestedLabwareDef: null },
],
})

expect(result[0].moduleChildren).toBeNull()
expect(result[0].highlight).toBeNull()
})
})

Expand Down Expand Up @@ -139,14 +135,12 @@ describe('getRunCurrentLabwareOnDeck', () => {
{
labwareLocation: { slotName: 'A1' },
definition: mockLabwareDef,
labwareChildren: (
<LabwareHighlight highlight={true} definition={mockLabwareDef} />
),
highlight: 'A1',
},
])
})

it('should set labwareChildren to null if getIsLabwareMatch returns false', () => {
it('should set highlight to null if getIsLabwareMatch returns false', () => {
const result = getRunCurrentLabwareOnDeck({
failedLabwareUtils: {
...mockFailedLabwareUtils,
Expand All @@ -158,7 +152,7 @@ describe('getRunCurrentLabwareOnDeck', () => {
currentLabwareInfo: [mockCurrentLabwareInfo],
})

expect(result[0].labwareChildren).toBeNull()
expect(result[0].highlight).toBeNull()
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {
THERMOCYCLER_MODULE_V1,
} from '@opentrons/shared-data'

import { LabwareHighlight } from '../shared'

import type { Run } from '@opentrons/api-client'
import type {
DeckDefinition,
Expand All @@ -21,29 +19,33 @@ import type {
LabwareLocation,
CutoutConfigProtocolSpec,
LoadedLabware,
RobotType,
} from '@opentrons/shared-data'
import type { ErrorRecoveryFlowsProps } from '..'
import type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils'

interface UseRecoveryMapUtilsProps {
interface UseDeckMapUtilsProps {
runId: ErrorRecoveryFlowsProps['runId']
protocolAnalysis: ErrorRecoveryFlowsProps['protocolAnalysis']
failedLabwareUtils: UseFailedLabwareUtilsResult
runRecord?: Run
}

export interface UseRecoveryMapUtilsResult {
export interface UseDeckMapUtilsResult {
deckConfig: CutoutConfigProtocolSpec[]
runCurrentModules: RunCurrentModulesOnDeck[]
runCurrentLabware: RunCurrentLabwareOnDeck[]
modulesOnDeck: RunCurrentModulesOnDeck[]
labwareOnDeck: RunCurrentLabwareOnDeck[]
highlightLabwareEventuallyIn: string[]
kind: 'intervention'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just want to make sure we always want the kind to be intervention?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. in this case we do because this is only picked up by error recovery use cases which always use that style of deck map. the deck config style is only used by the drop tip wiz

robotType: RobotType
}
// Returns the utilities needed by the Recovery Deck Map.
export function useRecoveryMapUtils({
export function useDeckMapUtils({
protocolAnalysis,
runRecord,
runId,
failedLabwareUtils,
}: UseRecoveryMapUtilsProps): UseRecoveryMapUtilsResult {
}: UseDeckMapUtilsProps): UseDeckMapUtilsResult {
const robotType = protocolAnalysis?.robotType ?? OT2_ROBOT_TYPE
const deckConfig = getSimplestDeckConfigForProtocol(protocolAnalysis)
const deckDef = getDeckDefFromRobotType(robotType)
Expand Down Expand Up @@ -83,8 +85,23 @@ export function useRecoveryMapUtils({

return {
deckConfig,
runCurrentModules,
runCurrentLabware,
modulesOnDeck: runCurrentModules.map(
({ moduleModel, moduleLocation, innerProps, nestedLabwareDef }) => ({
moduleModel,
moduleLocation,
innerProps,
nestedLabwareDef,
})
),
labwareOnDeck: runCurrentLabware.map(({ labwareLocation, definition }) => ({
labwareLocation,
definition,
})),
highlightLabwareEventuallyIn: [...runCurrentModules, ...runCurrentLabware]
.map(el => el.highlight)
.filter(maybeSlot => maybeSlot != null) as string[],
kind: 'intervention',
robotType,
}
}

Expand All @@ -101,70 +118,56 @@ interface RunCurrentModulesOnDeck {
lidMotorState?: undefined
}
nestedLabwareDef: LabwareDefinition2 | null
moduleChildren: JSX.Element | null
}

// Builds the necessary module object expected by BaseDeck.
export function getRunCurrentModulesOnDeck({
failedLabwareUtils,
currentModulesInfo,
}: {
failedLabwareUtils: UseRecoveryMapUtilsProps['failedLabwareUtils']
failedLabwareUtils: UseDeckMapUtilsProps['failedLabwareUtils']
currentModulesInfo: RunCurrentModuleInfo[]
}): RunCurrentModulesOnDeck[] {
}): Array<RunCurrentModulesOnDeck & { highlight: string | null }> {
const { failedLabware } = failedLabwareUtils

return currentModulesInfo.map(
({ moduleDef, slotName, nestedLabwareDef, nestedLabwareSlotName }) => {
const isLabwareMatch = getIsLabwareMatch(
nestedLabwareSlotName,
failedLabware
)

return {
moduleModel: moduleDef.model,
moduleLocation: { slotName },
innerProps:
moduleDef.model === THERMOCYCLER_MODULE_V1
? { lidMotorState: 'open' }
: {},

nestedLabwareDef,
moduleChildren:
isLabwareMatch && nestedLabwareDef != null ? (
<LabwareHighlight highlight={true} definition={nestedLabwareDef} />
) : null,
}
}
({ moduleDef, slotName, nestedLabwareDef, nestedLabwareSlotName }) => ({
moduleModel: moduleDef.model,
moduleLocation: { slotName },
innerProps:
moduleDef.model === THERMOCYCLER_MODULE_V1
? { lidMotorState: 'open' }
: {},

nestedLabwareDef,
highlight: getIsLabwareMatch(nestedLabwareSlotName, failedLabware)
? nestedLabwareSlotName
: null,
})
)
}

interface RunCurrentLabwareOnDeck {
labwareLocation: LabwareLocation
definition: LabwareDefinition2
labwareChildren: JSX.Element | null
}
// Builds the necessary labware object expected by BaseDeck.
export function getRunCurrentLabwareOnDeck({
currentLabwareInfo,
failedLabwareUtils,
}: {
failedLabwareUtils: UseRecoveryMapUtilsProps['failedLabwareUtils']
failedLabwareUtils: UseDeckMapUtilsProps['failedLabwareUtils']
currentLabwareInfo: RunCurrentLabwareInfo[]
}): RunCurrentLabwareOnDeck[] {
}): Array<RunCurrentLabwareOnDeck & { highlight: string | null }> {
const { failedLabware } = failedLabwareUtils

return currentLabwareInfo.map(({ slotName, labwareDef, labwareLocation }) => {
const isLabwareMatch = getIsLabwareMatch(slotName, failedLabware)

return {
return currentLabwareInfo.map(
({ slotName, labwareDef, labwareLocation }) => ({
labwareLocation,
definition: labwareDef,
labwareChildren: isLabwareMatch ? (
<LabwareHighlight highlight={true} definition={labwareDef} />
) : null,
}
})
highlight: getIsLabwareMatch(slotName, failedLabware) ? slotName : null,
})
)
}

interface RunCurrentModuleInfo {
Expand All @@ -181,8 +184,8 @@ export const getRunCurrentModulesInfo = ({
deckDef,
protocolAnalysis,
}: {
protocolAnalysis: UseRecoveryMapUtilsProps['protocolAnalysis']
runRecord: UseRecoveryMapUtilsProps['runRecord']
protocolAnalysis: UseDeckMapUtilsProps['protocolAnalysis']
runRecord: UseDeckMapUtilsProps['runRecord']
deckDef: DeckDefinition
}): RunCurrentModuleInfo[] => {
if (runRecord == null || protocolAnalysis == null) {
Expand Down Expand Up @@ -248,8 +251,8 @@ export function getRunCurrentLabwareInfo({
runRecord,
protocolAnalysis,
}: {
runRecord: UseRecoveryMapUtilsProps['runRecord']
protocolAnalysis: UseRecoveryMapUtilsProps['protocolAnalysis']
runRecord: UseDeckMapUtilsProps['runRecord']
protocolAnalysis: UseDeckMapUtilsProps['protocolAnalysis']
}): RunCurrentLabwareInfo[] {
if (runRecord == null || protocolAnalysis == null) {
return []
Expand Down
10 changes: 5 additions & 5 deletions app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useRecoveryTipStatus } from './useRecoveryTipStatus'
import { useRecoveryRouting } from './useRecoveryRouting'
import { useFailedLabwareUtils } from './useFailedLabwareUtils'
import { getFailedCommandPipetteInfo, getNextStep } from '../utils'
import { useRecoveryMapUtils } from './useRecoveryMapUtils'
import { useDeckMapUtils } from './useDeckMapUtils'
import {
useNotifyAllCommandsQuery,
useNotifyRunQuery,
Expand All @@ -21,7 +21,7 @@ import type { UseRouteUpdateActionsResult } from './useRouteUpdateActions'
import type { UseRecoveryCommandsResult } from './useRecoveryCommands'
import type { RecoveryTipStatusUtils } from './useRecoveryTipStatus'
import type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils'
import type { UseRecoveryMapUtilsResult } from './useRecoveryMapUtils'
import type { UseDeckMapUtilsResult } from './useDeckMapUtils'
import type { CurrentRecoveryOptionUtils } from './useRecoveryRouting'
import type { StepCounts } from '../../../resources/protocols/hooks'

Expand All @@ -37,7 +37,7 @@ export interface ERUtilsResults {
recoveryCommands: UseRecoveryCommandsResult
tipStatusUtils: RecoveryTipStatusUtils
failedLabwareUtils: UseFailedLabwareUtilsResult
recoveryMapUtils: UseRecoveryMapUtilsResult
deckMapUtils: UseDeckMapUtilsResult
getRecoveryOptionCopy: ReturnType<typeof useRecoveryOptionCopy>
failedPipetteInfo: PipetteData | null
hasLaunchedRecovery: boolean
Expand Down Expand Up @@ -109,7 +109,7 @@ export function useERUtils({
routeUpdateActions,
})

const recoveryMapUtils = useRecoveryMapUtils({
const deckMapUtils = useDeckMapUtils({
runId,
runRecord,
protocolAnalysis,
Expand All @@ -133,7 +133,7 @@ export function useERUtils({
tipStatusUtils,
failedLabwareUtils,
failedPipetteInfo,
recoveryMapUtils,
deckMapUtils,
getRecoveryOptionCopy,
stepCounts,
commandAfterFailedCommand,
Expand Down
Loading