Skip to content

Commit

Permalink
fix(app): Inject labware definitions into Error Recovery (#17248)
Browse files Browse the repository at this point in the history
Closes RQA-3814
  • Loading branch information
mjhuff authored Jan 10, 2025
1 parent 3a46ebe commit ec49410
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export function RunHeaderModalContainer(
runStatus={runStatus}
runId={runId}
unvalidatedFailedCommand={recoveryModalUtils.failedCommand}
runLwDefsByUri={recoveryModalUtils.runLwDefsByUri}
protocolAnalysis={robotProtocolAnalysis}
/>
) : null}
Expand Down
1 change: 1 addition & 0 deletions app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const mockRecoveryContentProps: RecoveryContentProps = {
byRunRecord: mockFailedCommand,
byAnalysis: mockFailedCommand,
},
runLwDefsByUri: {} as any,
errorKind: 'GENERAL_ERROR',
robotType: FLEX_ROBOT_TYPE,
runId: 'MOCK_RUN_ID',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ vi.mock('react-redux', async () => {
describe('useErrorRecoveryFlows', () => {
beforeEach(() => {
vi.mocked(useCurrentlyRecoveringFrom).mockReturnValue('mockCommand' as any)
vi.mocked(useRunLoadedLabwareDefinitionsByUri).mockReturnValue({})
})

it('should have initial state of isERActive as false', () => {
Expand Down Expand Up @@ -89,12 +90,32 @@ describe('useErrorRecoveryFlows', () => {
expect(result.current.failedCommand).toEqual('mockCommand')
})

it("should return the run's labware definitions", () => {
const { result } = renderHook(() =>
useErrorRecoveryFlows('MOCK_ID', RUN_STATUS_RUNNING)
)

expect(result.current.failedCommand).toEqual('mockCommand')
})

it(`should return isERActive false if the run status is ${RUN_STATUS_STOP_REQUESTED} before seeing ${RUN_STATUS_AWAITING_RECOVERY}`, () => {
const { result } = renderHook(() =>
useErrorRecoveryFlows('MOCK_ID', RUN_STATUS_STOP_REQUESTED)
)

expect(result.current.isERActive).toEqual(false)
expect(result.current.runLwDefsByUri).toEqual({})
})

it('should not return isERActive if the run labware defintions is null', () => {
vi.mocked(useRunLoadedLabwareDefinitionsByUri).mockReturnValue(null)

const { result } = renderHook(
runStatus => useErrorRecoveryFlows('MOCK_ID', runStatus),
{
initialProps: RUN_STATUS_AWAITING_RECOVERY,
}
)
expect(result.current.isERActive).toBe(false)
})

it('should set hasSeenAwaitingRecovery to true when runStatus is RUN_STATUS_AWAITING_RECOVERY', () => {
Expand Down Expand Up @@ -143,6 +164,7 @@ describe('ErrorRecoveryFlows', () => {
unvalidatedFailedCommand: mockFailedCommand,
runId: 'MOCK_RUN_ID',
protocolAnalysis: null,
runLwDefsByUri: {},
}
vi.mocked(ErrorRecoveryWizard).mockReturnValue(<div>MOCK WIZARD</div>)
vi.mocked(RecoverySplash).mockReturnValue(<div>MOCK RUN PAUSED SPLASH</div>)
Expand All @@ -167,7 +189,6 @@ describe('ErrorRecoveryFlows', () => {
intent: 'recovering',
showTakeover: false,
})
vi.mocked(useRunLoadedLabwareDefinitionsByUri).mockReturnValue({})
})

it('renders the wizard when showERWizard is true', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,17 +198,7 @@ describe('getRunCurrentModulesInfo', () => {
const result = getRunCurrentModulesInfo({
runRecord: null as any,
deckDef: mockDeckDef,
labwareDefinitionsByUri: {},
})

expect(result).toEqual([])
})

it('should return an empty array if protocolAnalysis is null', () => {
const result = getRunCurrentModulesInfo({
runRecord: mockRunRecord,
deckDef: mockDeckDef,
labwareDefinitionsByUri: null,
runLwDefsByUri: {},
})

expect(result).toEqual([])
Expand All @@ -219,7 +209,7 @@ describe('getRunCurrentModulesInfo', () => {
const result = getRunCurrentModulesInfo({
runRecord: mockRunRecord,
deckDef: mockDeckDef,
labwareDefinitionsByUri: {
runLwDefsByUri: {
'opentrons/opentrons_96_pcr_adapter/1': 'MOCK_LW_DEF',
} as any,
})
Expand All @@ -242,7 +232,7 @@ describe('getRunCurrentModulesInfo', () => {
data: { modules: [mockModule], labware: [] },
},
deckDef: mockDeckDef,
labwareDefinitionsByUri: {},
runLwDefsByUri: {},
})
expect(result).toEqual([
{
Expand All @@ -261,7 +251,7 @@ describe('getRunCurrentModulesInfo', () => {
const result = getRunCurrentModulesInfo({
runRecord: mockRunRecord,
deckDef: mockDeckDef,
labwareDefinitionsByUri: null,
runLwDefsByUri: {},
})
expect(result).toEqual([])
})
Expand All @@ -286,7 +276,7 @@ describe('getRunCurrentLabwareInfo', () => {
it('should return an empty array if runRecord is null', () => {
const result = getRunCurrentLabwareInfo({
runRecord: undefined,
labwareDefinitionsByUri: {} as any,
runLwDefsByUri: {} as any,
})

expect(result).toEqual([])
Expand All @@ -295,7 +285,7 @@ describe('getRunCurrentLabwareInfo', () => {
it('should return an empty array if protocolAnalysis is null', () => {
const result = getRunCurrentLabwareInfo({
runRecord: { data: { labware: [] } } as any,
labwareDefinitionsByUri: null,
runLwDefsByUri: {},
})

expect(result).toEqual([])
Expand All @@ -309,7 +299,7 @@ describe('getRunCurrentLabwareInfo', () => {

const result = getRunCurrentLabwareInfo({
runRecord: { data: { labware: [mockPickUpTipLwSlotName] } } as any,
labwareDefinitionsByUri: {
runLwDefsByUri: {
[mockPickUpTipLabware.definitionUri]: mockLabwareDef,
},
})
Expand Down
52 changes: 22 additions & 30 deletions app/src/organisms/ErrorRecoveryFlows/hooks/useDeckMapUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interface UseDeckMapUtilsProps {
runId: ErrorRecoveryFlowsProps['runId']
protocolAnalysis: ErrorRecoveryFlowsProps['protocolAnalysis']
failedLabwareUtils: UseFailedLabwareUtilsResult
labwareDefinitionsByUri: ERUtilsProps['labwareDefinitionsByUri']
runLwDefsByUri: ERUtilsProps['runLwDefsByUri']
runRecord: Run | undefined
}

Expand All @@ -65,7 +65,7 @@ export function useDeckMapUtils({
runRecord,
runId,
failedLabwareUtils,
labwareDefinitionsByUri,
runLwDefsByUri,
}: UseDeckMapUtilsProps): UseDeckMapUtilsResult {
const robotType = protocolAnalysis?.robotType ?? OT2_ROBOT_TYPE
const deckConfig = getSimplestDeckConfigForProtocol(protocolAnalysis)
Expand All @@ -78,9 +78,9 @@ export function useDeckMapUtils({
getRunCurrentModulesInfo({
runRecord,
deckDef,
labwareDefinitionsByUri,
runLwDefsByUri,
}),
[runRecord, deckDef, labwareDefinitionsByUri]
[runRecord, deckDef, runLwDefsByUri]
)

const runCurrentModules = useMemo(
Expand All @@ -94,8 +94,8 @@ export function useDeckMapUtils({
)

const currentLabwareInfo = useMemo(
() => getRunCurrentLabwareInfo({ runRecord, labwareDefinitionsByUri }),
[runRecord, labwareDefinitionsByUri]
() => getRunCurrentLabwareInfo({ runRecord, runLwDefsByUri }),
[runRecord, runLwDefsByUri]
)

const { updatedModules, remainingLabware } = useMemo(
Expand All @@ -114,32 +114,24 @@ export function useDeckMapUtils({
)

const movedLabwareDef =
labwareDefinitionsByUri != null && failedLabwareUtils.failedLabware != null
? labwareDefinitionsByUri[failedLabwareUtils.failedLabware.definitionUri]
runLwDefsByUri != null && failedLabwareUtils.failedLabware != null
? runLwDefsByUri[failedLabwareUtils.failedLabware.definitionUri]
: null

const moduleRenderInfo = useMemo(
() =>
runRecord != null && labwareDefinitionsByUri != null
? getRunModuleRenderInfo(
runRecord.data,
deckDef,
labwareDefinitionsByUri
)
runRecord != null && runLwDefsByUri != null
? getRunModuleRenderInfo(runRecord.data, deckDef, runLwDefsByUri)
: [],
[deckDef, labwareDefinitionsByUri, runRecord]
[deckDef, runLwDefsByUri, runRecord]
)

const labwareRenderInfo = useMemo(
() =>
runRecord != null && labwareDefinitionsByUri != null
? getRunLabwareRenderInfo(
runRecord.data,
labwareDefinitionsByUri,
deckDef
)
runRecord != null && runLwDefsByUri != null
? getRunLabwareRenderInfo(runRecord.data, runLwDefsByUri, deckDef)
: [],
[deckDef, labwareDefinitionsByUri, runRecord]
[deckDef, runLwDefsByUri, runRecord]
)

return {
Expand Down Expand Up @@ -258,13 +250,13 @@ interface RunCurrentModuleInfo {
export const getRunCurrentModulesInfo = ({
runRecord,
deckDef,
labwareDefinitionsByUri,
runLwDefsByUri,
}: {
runRecord: UseDeckMapUtilsProps['runRecord']
deckDef: DeckDefinition
labwareDefinitionsByUri?: LabwareDefinitionsByUri | null
runLwDefsByUri: UseDeckMapUtilsProps['runLwDefsByUri']
}): RunCurrentModuleInfo[] => {
if (runRecord == null || labwareDefinitionsByUri == null) {
if (runRecord == null) {
return []
} else {
return runRecord.data.modules.reduce<RunCurrentModuleInfo[]>(
Expand All @@ -281,7 +273,7 @@ export const getRunCurrentModulesInfo = ({

const nestedLabwareDef =
nestedLabware != null
? labwareDefinitionsByUri[nestedLabware.definitionUri]
? runLwDefsByUri[nestedLabware.definitionUri]
: null

const slotPosition = getPositionFromSlotId(
Expand Down Expand Up @@ -325,12 +317,12 @@ interface RunCurrentLabwareInfo {
// Derive the labware info necessary to render labware on the deck.
export function getRunCurrentLabwareInfo({
runRecord,
labwareDefinitionsByUri,
runLwDefsByUri,
}: {
runRecord: UseDeckMapUtilsProps['runRecord']
labwareDefinitionsByUri?: LabwareDefinitionsByUri | null
runLwDefsByUri: UseDeckMapUtilsProps['runLwDefsByUri']
}): RunCurrentLabwareInfo[] {
if (runRecord == null || labwareDefinitionsByUri == null) {
if (runRecord == null) {
return []
} else {
const allLabware = runRecord.data.labware.reduce(
Expand All @@ -341,7 +333,7 @@ export function getRunCurrentLabwareInfo({
runRecord,
true
) // Exclude modules since handled separately.
const labwareDef = getLabwareDefinition(lw, labwareDefinitionsByUri)
const labwareDef = getLabwareDefinition(lw, runLwDefsByUri)

if (slotName == null || labwareLocation == null) {
return acc
Expand Down
11 changes: 3 additions & 8 deletions app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ import { useCleanupRecoveryState } from './useCleanupRecoveryState'
import { useFailedPipetteUtils } from './useFailedPipetteUtils'
import { getRunningStepCountsFrom } from '/app/resources/protocols'

import type {
LabwareDefinition2,
LabwareDefinitionsByUri,
RobotType,
} from '@opentrons/shared-data'
import type { LabwareDefinition2, RobotType } from '@opentrons/shared-data'
import type { IRecoveryMap, RouteStep, RecoveryRoute } from '../types'
import type { ErrorRecoveryFlowsProps } from '..'
import type { UseRouteUpdateActionsResult } from './useRouteUpdateActions'
Expand Down Expand Up @@ -54,7 +50,6 @@ export type ERUtilsProps = Omit<ErrorRecoveryFlowsProps, 'failedCommand'> & {
failedCommand: ReturnType<typeof useRetainedFailedCommandBySource>
isActiveUser: UseRecoveryTakeoverResult['isActiveUser']
allRunDefs: LabwareDefinition2[]
labwareDefinitionsByUri: LabwareDefinitionsByUri | null
}

export interface ERUtilsResults {
Expand Down Expand Up @@ -90,7 +85,7 @@ export function useERUtils({
isActiveUser,
allRunDefs,
unvalidatedFailedCommand,
labwareDefinitionsByUri,
runLwDefsByUri,
}: ERUtilsProps): ERUtilsResults {
const { data: attachedInstruments } = useInstrumentsQuery()
const { data: runRecord } = useNotifyRunQuery(runId)
Expand Down Expand Up @@ -185,7 +180,7 @@ export function useERUtils({
runRecord,
protocolAnalysis,
failedLabwareUtils,
labwareDefinitionsByUri,
runLwDefsByUri,
})

const recoveryActionMutationUtils = useRecoveryActionMutation(
Expand Down
Loading

0 comments on commit ec49410

Please sign in to comment.