Skip to content

Commit

Permalink
fix(app): disable rerun until data is available (#16154)
Browse files Browse the repository at this point in the history
We need the full run data to rerun a run, but that can be pretty
significantly delayed on USB. Add a loading state for that button
(disabled with a new tooltip) in that case.

Close RQA-3117

## testing
- [x] does this fix the issue
- [x] why is the tooltip like that
  • Loading branch information
sfoster1 authored Aug 29, 2024
1 parent b5eb91d commit f208e93
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 16 deletions.
1 change: 1 addition & 0 deletions app/src/assets/localization/en/device_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"recalibrate_pipette": "Recalibrate pipette",
"recent_protocol_runs": "Recent Protocol Runs",
"rerun_now": "Rerun protocol now",
"rerun_loading": "Protocol re-run is disabled until data connection fully loads",
"reset_all": "Reset all",
"reset_estop": "Reset E-stop",
"resume_operation": "Resume operation",
Expand Down
11 changes: 9 additions & 2 deletions app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element {
}
const trackEvent = useTrackEvent()
const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName)
const { reset } = useRunControls(runId, onResetSuccess)
const { reset, isRunControlLoading } = useRunControls(runId, onResetSuccess)
const { deleteRun } = useDeleteRunMutation()
const robot = useRobot(robotName)
const robotSerialNumber =
Expand Down Expand Up @@ -184,7 +184,9 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element {
<MenuItem
{...targetProps}
onClick={handleResetClick}
disabled={robotIsBusy || isRobotOnWrongVersionOfSoftware}
disabled={
robotIsBusy || isRobotOnWrongVersionOfSoftware || isRunControlLoading
}
data-testid="RecentProtocolRun_OverflowMenu_rerunNow"
>
{t('rerun_now')}
Expand All @@ -194,6 +196,11 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element {
{t('shared:a_software_update_is_available')}
</Tooltip>
)}
{isRunControlLoading && (
<Tooltip whiteSpace="normal" tooltipProps={tooltipProps}>
{t('rerun_loading')}
</Tooltip>
)}
<MenuItem
data-testid="RecentProtocolRun_OverflowMenu_downloadRunLog"
disabled={isRunLogLoading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ describe('ProtocolRunHeader', () => {
isStopRunActionLoading: false,
isResetRunLoading: false,
isResumeRunFromRecoveryActionLoading: false,
isRunControlLoading: false,
})
when(vi.mocked(useRunStatus)).calledWith(RUN_ID).thenReturn(RUN_STATUS_IDLE)
when(vi.mocked(useRunTimestamps)).calledWith(RUN_ID).thenReturn({
Expand Down Expand Up @@ -848,6 +849,7 @@ describe('ProtocolRunHeader', () => {
isStopRunActionLoading: false,
isResetRunLoading: true,
isResumeRunFromRecoveryActionLoading: false,
isRunControlLoading: false,
})
render()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe('HistoricalProtocolRunOverflowMenu', () => {
isStopRunActionLoading: false,
isResetRunLoading: false,
isResumeRunFromRecoveryActionLoading: false,
isRunControlLoading: false,
})
when(useNotifyAllCommandsQuery)
.calledWith(
Expand Down Expand Up @@ -154,6 +155,32 @@ describe('HistoricalProtocolRunOverflowMenu', () => {
expect(rerunBtn).toBeDisabled()
})

it('disables the rerun protocol menu item if run data is loading', () => {
when(useRunControls)
.calledWith(RUN_ID, expect.anything())
.thenReturn({
play: () => {},
pause: () => {},
stop: () => {},
reset: () => {},
resumeFromRecovery: () => {},
isPlayRunActionLoading: false,
isPauseRunActionLoading: false,
isStopRunActionLoading: false,
isResetRunLoading: false,
isResumeRunFromRecoveryActionLoading: false,
isRunControlLoading: true,
})
render(props)
const btn = screen.getByRole('button')
fireEvent.click(btn)
screen.getByRole('button', {
name: 'View protocol run record',
})
const rerunBtn = screen.getByRole('button', { name: 'Rerun protocol now' })
expect(rerunBtn).toBeDisabled()
})

it('should make overflow menu disabled when e-stop is pressed', () => {
when(useIsEstopNotDisengaged).calledWith(ROBOT_NAME).thenReturn(true)
render(props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ describe('RecentRunProtocolCard', () => {
})
vi.mocked(useCloneRun).mockReturnValue({
cloneRun: mockCloneRun,
isLoading: false,
isLoadingRun: false,
isCloning: false,
})
})

Expand Down
10 changes: 5 additions & 5 deletions app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import type { Run } from '@opentrons/api-client'

interface UseCloneRunResult {
cloneRun: () => void
isLoading: boolean
isLoadingRun: boolean
isCloning: boolean
}

export function useCloneRun(
Expand All @@ -25,10 +26,9 @@ export function useCloneRun(
): UseCloneRunResult {
const host = useHost()
const queryClient = useQueryClient()
const { data: runRecord } = useNotifyRunQuery(runId)
const { data: runRecord, isLoading: isLoadingRun } = useNotifyRunQuery(runId)
const protocolKey = runRecord?.data.protocolId ?? null

const { createRun, isLoading } = useCreateRunMutation({
const { createRun, isLoading: isCloning } = useCreateRunMutation({
onSuccess: response => {
const invalidateRuns = queryClient.invalidateQueries([host, 'runs'])
const invalidateProtocols = queryClient.invalidateQueries([
Expand Down Expand Up @@ -80,5 +80,5 @@ export function useCloneRun(
}
}

return { cloneRun, isLoading }
return { cloneRun, isLoadingRun, isCloning }
}
8 changes: 5 additions & 3 deletions app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ describe('useRunControls hook', () => {
isStopRunActionLoading: false,
isResumeRunFromRecoveryActionLoading: false,
})
when(useCloneRun)
.calledWith(mockPausedRun.id, undefined, true)
.thenReturn({ cloneRun: mockCloneRun, isLoading: false })
when(useCloneRun).calledWith(mockPausedRun.id, undefined, true).thenReturn({
cloneRun: mockCloneRun,
isCloning: false,
isLoadingRun: false,
})

const { result } = renderHook(() => useRunControls(mockPausedRun.id))

Expand Down
12 changes: 7 additions & 5 deletions app/src/organisms/RunTimeControl/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface RunControls {
isStopRunActionLoading: boolean
isResumeRunFromRecoveryActionLoading: boolean
isResetRunLoading: boolean
isRunControlLoading: boolean
}

export function useRunControls(
Expand All @@ -51,11 +52,11 @@ export function useRunControls(
isResumeRunFromRecoveryActionLoading,
} = useRunActionMutations(runId as string)

const { cloneRun, isLoading: isResetRunLoading } = useCloneRun(
runId ?? null,
onCloneRunSuccess,
true
)
const {
cloneRun,
isLoadingRun: isRunControlLoading,
isCloning: isResetRunLoading,
} = useCloneRun(runId ?? null, onCloneRunSuccess, true)

return {
play: playRun,
Expand All @@ -67,6 +68,7 @@ export function useRunControls(
isPauseRunActionLoading,
isStopRunActionLoading,
isResumeRunFromRecoveryActionLoading,
isRunControlLoading,
isResetRunLoading,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ describe('ProtocolSetup', () => {
isStopRunActionLoading: false,
isResetRunLoading: false,
isResumeRunFromRecoveryActionLoading: false,
isRunControlLoading: false,
})
when(vi.mocked(useRunStatus)).calledWith(RUN_ID).thenReturn(RUN_STATUS_IDLE)
vi.mocked(useProtocolAnalysisAsDocumentQuery).mockReturnValue({
Expand Down

0 comments on commit f208e93

Please sign in to comment.