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

fix(app): Delineate failed command source #15933

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const getPipettingCommandText = ({
robotType
)
: ''

switch (command?.commandType) {
case 'aspirate': {
const { volume, flowRate } = command.params
Expand Down
63 changes: 35 additions & 28 deletions app/src/molecules/InterventionModal/CategorizedStepContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,35 +111,42 @@ export function CategorizedStepContent(
justifyContent={JUSTIFY_FLEX_START}
gap={SPACING.spacing4}
>
<StyledText oddStyle="bodyTextSemiBold" desktopStyle="captionSemiBold">
{props.bottomCategoryHeadline}
</StyledText>
{props.bottomCategoryCommands.map((command, idx) => (
<Flex
gap={SPACING.spacing8}
key={`${props.bottomCategory}${
command?.command?.commandType ?? 'unknown'
}${idx}`}
css={idx > 0 ? HIDE_ON_TOUCHSCREEN_STYLE : undefined}
{props.bottomCategoryCommands[0] != null ? (
<StyledText
oddStyle="bodyTextSemiBold"
desktopStyle="captionSemiBold"
>
<CommandIndex
index={`${
command?.index == null ? '' : command.index.toString()
}`}
allowSpaceForNDigits={maxIndexLength}
/>
<Command
{...commandAndState(
command,
props.bottomCategory,
props.commandTextData
)}
robotType={props.robotType}
aligned="left"
forceTwoLineClip
/>
</Flex>
))}
{props.bottomCategoryHeadline}
</StyledText>
) : null}
{props.bottomCategoryCommands.map((command, idx) => {
return command != null ? (
<Flex
gap={SPACING.spacing8}
key={`${props.bottomCategory}${
command?.command?.commandType ?? 'unknown'
}${idx}`}
css={idx > 0 ? HIDE_ON_TOUCHSCREEN_STYLE : undefined}
>
<CommandIndex
index={`${
command?.index == null ? '' : command.index.toString()
}`}
allowSpaceForNDigits={maxIndexLength}
/>
<Command
{...commandAndState(
command,
props.bottomCategory,
props.commandTextData
)}
robotType={props.robotType}
aligned="left"
forceTwoLineClip
/>
</Flex>
) : null
})}
</Flex>
</Flex>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ export function ProtocolRunHeader({
<ErrorRecoveryFlows
runStatus={runStatus}
runId={runId}
failedCommand={failedCommand}
failedCommandByRunRecord={failedCommand}
protocolAnalysis={robotProtocolAnalysis}
/>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import { RECOVERY_MAP } from './constants'

import type { RobotType } from '@opentrons/shared-data'
import type { RecoveryContentProps } from './types'
import type { ERUtilsResults, UseRecoveryAnalyticsResult } from './hooks'
import type {
ERUtilsResults,
UseRecoveryAnalyticsResult,
useRetainedFailedCommandBySource,
} from './hooks'
import type { ErrorRecoveryFlowsProps } from '.'

export interface UseERWizardResult {
Expand Down Expand Up @@ -65,6 +69,7 @@ export type ErrorRecoveryWizardProps = ErrorRecoveryFlowsProps &
isOnDevice: boolean
isDoorOpen: boolean
analytics: UseRecoveryAnalyticsResult
failedCommand: ReturnType<typeof useRetainedFailedCommandBySource>
}

export function ErrorRecoveryWizard(
Expand All @@ -76,7 +81,7 @@ export function ErrorRecoveryWizard(
recoveryCommands,
routeUpdateActions,
} = props
const errorKind = getErrorKind(failedCommand)
const errorKind = getErrorKind(failedCommand?.byRunRecord ?? null)

useInitialPipetteHome({
hasLaunchedRecovery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export function useDropTipFlowUtils({
const { selectedRecoveryOption } = currentRecoveryOptionUtils
const { proceedToRouteAndStep } = routeUpdateActions
const { updateSubMap, subMap } = subMapUtils
const failedCommandId = failedCommand?.id ?? '' // We should have a failed command here unless the run is not in AWAITING_RECOVERY.
const failedCommandId = failedCommand?.byRunRecord.id ?? '' // We should have a failed command here unless the run is not in AWAITING_RECOVERY.

const buildTipDropCompleteBtn = (): string => {
switch (selectedRecoveryOption) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,11 @@ describe('useDropTipFlowUtils', () => {
const { result } = renderHook(() =>
useDropTipFlowUtils({
...mockProps,
failedCommand: { id: 'MOCK_COMMAND_ID' },
failedCommand: {
byRunRecord: {
id: 'MOCK_COMMAND_ID',
},
},
} as any)
)

Expand Down
5 changes: 3 additions & 2 deletions app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type {
ERUtilsResults,
UseRecoveryAnalyticsResult,
UseRecoveryTakeoverResult,
useRetainedFailedCommandBySource,
} from './hooks'

export function useRunPausedSplash(
Expand All @@ -54,7 +55,7 @@ export function useRunPausedSplash(

type RunPausedSplashProps = ERUtilsResults & {
isOnDevice: boolean
failedCommand: ErrorRecoveryFlowsProps['failedCommand']
failedCommand: ReturnType<typeof useRetainedFailedCommandBySource>
protocolAnalysis: ErrorRecoveryFlowsProps['protocolAnalysis']
robotType: RobotType
robotName: string
Expand All @@ -73,7 +74,7 @@ export function RunPausedSplash(
robotName,
} = props
const { t } = useTranslation('error_recovery')
const errorKind = getErrorKind(failedCommand)
const errorKind = getErrorKind(failedCommand?.byRunRecord ?? null)
const title = useErrorName(errorKind)

const { proceedToRouteAndStep } = routeUpdateActions
Expand Down
8 changes: 6 additions & 2 deletions app/src/organisms/ErrorRecoveryFlows/__fixtures__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ export const mockPickUpTipLabware: LoadedLabware = {
displayName: 'MOCK_PickUpTipLabware_NAME',
}

// TOME: Add the mock labware and pipette, etc. as you end up using it elsewhere to here.
// TODO: jh(08-07-24): update the "byAnalysis" mockFailedCommand.
export const mockRecoveryContentProps: RecoveryContentProps = {
failedCommand: mockFailedCommand,
failedCommandByRunRecord: mockFailedCommand,
failedCommand: {
byRunRecord: mockFailedCommand,
byAnalysis: mockFailedCommand,
},
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 @@ -138,7 +138,7 @@ describe('ErrorRecoveryFlows', () => {
beforeEach(() => {
props = {
runStatus: RUN_STATUS_AWAITING_RECOVERY,
failedCommand: mockFailedCommand,
failedCommandByRunRecord: mockFailedCommand,
runId: 'MOCK_RUN_ID',
protocolAnalysis: {} as any,
}
Expand Down Expand Up @@ -218,9 +218,11 @@ describe('ErrorRecoveryFlows', () => {

const newProps = {
...props,
failedCommand: null,
failedCommandByRunRecord: null,
}
rerender(<ErrorRecoveryFlows {...newProps} />)
expect(mockReportErrorEvent).toHaveBeenCalledWith(newProps.failedCommand)
expect(mockReportErrorEvent).toHaveBeenCalledWith(
newProps.failedCommandByRunRecord
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,11 @@ describe('RunPausedSplash', () => {
props = {
...props,
failedCommand: {
...props.failedCommand,
commandType: 'aspirate',
error: { isDefined: true, errorType: 'overpressure' },
byRunRecord: {
...props.failedCommand?.byRunRecord,
commandType: 'aspirate',
error: { isDefined: true, errorType: 'overpressure' },
},
} as any,
}
render(props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('getRelevantFailedLabwareCmdFrom', () => {
},
}
const result = getRelevantFailedLabwareCmdFrom({
failedCommand: failedLiquidProbeCommand,
failedCommandByRunRecord: failedLiquidProbeCommand,
})
expect(result).toEqual(failedLiquidProbeCommand)
})
Expand All @@ -110,7 +110,7 @@ describe('getRelevantFailedLabwareCmdFrom', () => {

overpressureErrorKinds.forEach(([commandType, errorType]) => {
const result = getRelevantFailedLabwareCmdFrom({
failedCommand: {
failedCommandByRunRecord: {
...failedCommand,
commandType,
error: { isDefined: true, errorType },
Expand All @@ -122,7 +122,7 @@ describe('getRelevantFailedLabwareCmdFrom', () => {
})
it('should return null for GENERAL_ERROR error kind', () => {
const result = getRelevantFailedLabwareCmdFrom({
failedCommand: {
failedCommandByRunRecord: {
...failedCommand,
error: { errorType: 'literally anything else' },
},
Expand All @@ -132,7 +132,7 @@ describe('getRelevantFailedLabwareCmdFrom', () => {

it('should return null for unhandled error kinds', () => {
const result = getRelevantFailedLabwareCmdFrom({
failedCommand: {
failedCommandByRunRecord: {
...failedCommand,
error: { errorType: 'SOME_UNHANDLED_ERROR' },
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('useRecoveryCommands', () => {

const props = {
runId: mockRunId,
failedCommand: mockFailedCommand,
failedCommandByRunRecord: mockFailedCommand,
failedLabwareUtils: mockFailedLabwareUtils,
routeUpdateActions: mockRouteUpdateActions,
recoveryToastUtils: { makeSuccessToast: mockMakeSuccessToast } as any,
Expand Down Expand Up @@ -132,7 +132,7 @@ describe('useRecoveryCommands', () => {
const { result } = renderHook(() =>
useRecoveryCommands({
runId: mockRunId,
failedCommand: {
failedCommandByRunRecord: {
...mockFailedCommand,
commandType: inPlaceCommandType,
params: {
Expand Down Expand Up @@ -230,7 +230,7 @@ describe('useRecoveryCommands', () => {

const testProps = {
...props,
failedCommand: mockFailedCmdWithPipetteId,
failedCommandByRunRecord: mockFailedCmdWithPipetteId,
failedLabwareUtils: {
...mockFailedLabwareUtils,
failedLabware: mockFailedLabware,
Expand Down Expand Up @@ -271,7 +271,7 @@ describe('useRecoveryCommands', () => {

const testProps = {
...props,
failedCommand: mockFailedCommandWithError,
failedCommandByRunRecord: mockFailedCommandWithError,
}

const { result } = renderHook(() => useRecoveryCommands(testProps))
Expand Down
2 changes: 2 additions & 0 deletions app/src/organisms/ErrorRecoveryFlows/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { useRouteUpdateActions } from './useRouteUpdateActions'
export { useERUtils } from './useERUtils'
export { useRecoveryAnalytics } from './useRecoveryAnalytics'
export { useRecoveryTakeover } from './useRecoveryTakeover'
export { useRetainedFailedCommandBySource } from './useRetainedFailedCommandBySource'

export type { UseRouteUpdateActionsResult } from './useRouteUpdateActions'
export type { UseRecoveryCommandsResult } from './useRecoveryCommands'
Expand All @@ -15,3 +16,4 @@ export type { ERUtilsResults } from './useERUtils'
export type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils'
export type { UseRecoveryAnalyticsResult } from './useRecoveryAnalytics'
export type { UseRecoveryTakeoverResult } from './useRecoveryTakeover'
export type { FailedCommandBySource } from './useRetainedFailedCommandBySource'
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import type { FailedCommand } from '../types'

const ALL_COMMANDS_POLL_MS = 5000

// TODO(jh, 08-06-24): See EXEC-656.
const VALID_RECOVERY_FETCH_STATUSES = [
RUN_STATUS_AWAITING_RECOVERY,
RUN_STATUS_AWAITING_RECOVERY_BLOCKED_BY_OPEN_DOOR,
RUN_STATUS_AWAITING_RECOVERY_PAUSED,
] as Array<RunStatus | null>

// Return the `currentlyRecoveringFrom` command returned by the server, if any.
// Otherwise, returns null.
export function useCurrentlyRecoveringFrom(
Expand All @@ -20,11 +27,7 @@ export function useCurrentlyRecoveringFrom(
): FailedCommand | null {
// There can only be a currentlyRecoveringFrom command when the run is in recovery mode.
// In case we're falling back to polling, only enable queries when that is the case.
const isRunInRecoveryMode = ([
RUN_STATUS_AWAITING_RECOVERY,
RUN_STATUS_AWAITING_RECOVERY_BLOCKED_BY_OPEN_DOOR,
RUN_STATUS_AWAITING_RECOVERY_PAUSED,
] as Array<RunStatus | null>).includes(runStatus)
const isRunInRecoveryMode = VALID_RECOVERY_FETCH_STATUSES.includes(runStatus)

const { data: allCommandsQueryData } = useNotifyAllCommandsQuery(
runId,
Expand Down
11 changes: 7 additions & 4 deletions app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ import type { RecoveryActionMutationResult } from './useRecoveryActionMutation'
import type { StepCounts } from '../../../resources/protocols/hooks'
import type { UseRecoveryAnalyticsResult } from './useRecoveryAnalytics'
import type { UseRecoveryTakeoverResult } from './useRecoveryTakeover'
import type { useRetainedFailedCommandBySource } from './useRetainedFailedCommandBySource'

type ERUtilsProps = ErrorRecoveryFlowsProps & {
export type ERUtilsProps = Omit<ErrorRecoveryFlowsProps, 'failedCommand'> & {
toggleERWizAsActiveUser: UseRecoveryTakeoverResult['toggleERWizAsActiveUser']
hasLaunchedRecovery: boolean
isOnDevice: boolean
robotType: RobotType
analytics: UseRecoveryAnalyticsResult
failedCommand: ReturnType<typeof useRetainedFailedCommandBySource>
}

export interface ERUtilsResults {
Expand Down Expand Up @@ -83,6 +85,7 @@ export function useERUtils({
cursor: 0,
pageLength: 999,
})
const failedCommandByRunRecord = failedCommand?.byRunRecord ?? null

const stepCounts = useRunningStepCounts(runId, runCommands)

Expand Down Expand Up @@ -116,13 +119,13 @@ export function useERUtils({
})

const failedPipetteInfo = getFailedCommandPipetteInfo({
failedCommand,
failedCommandByRunRecord,
runRecord,
attachedInstruments,
})

const failedLabwareUtils = useFailedLabwareUtils({
failedCommand,
failedCommandByRunRecord,
protocolAnalysis,
failedPipetteInfo,
runRecord,
Expand All @@ -131,7 +134,7 @@ export function useERUtils({

const recoveryCommands = useRecoveryCommands({
runId,
failedCommand,
failedCommandByRunRecord,
failedLabwareUtils,
routeUpdateActions,
recoveryToastUtils,
Expand Down
Loading
Loading