Skip to content

Commit f6b6f4c

Browse files
committed
fix(app): allow completed runs when starting protocol
This means that people don't have to make sure to explicitly close the run context by clicking the x button in the post-run flow before picking a new robot to run. Use the current run's completed at timestamp to decide whether or not the run is complete for the purposes of idle. This requires fetching the current run, which we do by ID. Closes EXEC-519
1 parent 905258b commit f6b6f4c

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { getNetworkInterfaces, fetchStatus } from '../../redux/networking'
2222
import { appShellRequestor } from '../../redux/shell/remote'
2323
import OT2_PNG from '../../assets/images/OT2-R_HERO.png'
2424
import FLEX_PNG from '../../assets/images/FLEX.png'
25-
import { useNotifyAllRunsQuery } from '../../resources/runs'
25+
import { useCurrentRunId, useNotifyRunQuery } from '../../resources/runs'
2626

2727
import type { IconName } from '@opentrons/components'
2828
import type { Runs } from '@opentrons/api-client'
@@ -59,14 +59,15 @@ export function AvailableRobotOption(
5959
getRobotModelByName(state, robotName)
6060
)
6161

62-
const { data: runsData } = useNotifyAllRunsQuery(
63-
{ pageLength: 0 },
62+
const [isBusy, setIsBusy] = React.useState(true)
63+
64+
const currentRunId = useCurrentRunId(
6465
{
6566
onSuccess: data => {
66-
if ((data as Runs)?.links?.current != null)
67-
registerRobotBusyStatus({ type: 'robotIsBusy', robotName })
68-
else {
67+
const definitelyIdle = (data as Runs)?.links?.current == null
68+
if (definitelyIdle) {
6969
registerRobotBusyStatus({ type: 'robotIsIdle', robotName })
70+
setIsBusy(false)
7071
}
7172
},
7273
},
@@ -75,7 +76,28 @@ export function AvailableRobotOption(
7576
requestor: ip === OPENTRONS_USB ? appShellRequestor : undefined,
7677
}
7778
)
78-
const robotHasCurrentRun = runsData?.links?.current != null
79+
80+
useNotifyRunQuery(
81+
currentRunId,
82+
{
83+
onSuccess: data => {
84+
const busy = data?.data != null && data.data.completedAt == null
85+
registerRobotBusyStatus({
86+
type: busy ? 'robotIsBusy' : 'robotIsIdle',
87+
robotName,
88+
})
89+
setIsBusy(busy)
90+
},
91+
onError: () => {
92+
registerRobotBusyStatus({ type: 'robotIsIdle', robotName })
93+
setIsBusy(false)
94+
},
95+
},
96+
{
97+
hostname: ip,
98+
requestor: ip === OPENTRONS_USB ? appShellRequestor : undefined,
99+
}
100+
)
79101

80102
const { ethernet, wifi } = useSelector((state: State) =>
81103
getNetworkInterfaces(state, robotName)
@@ -95,7 +117,7 @@ export function AvailableRobotOption(
95117
// eslint-disable-next-line react-hooks/exhaustive-deps
96118
}, [])
97119

98-
return showIdleOnly && robotHasCurrentRun ? null : (
120+
return showIdleOnly && isBusy ? null : (
99121
<>
100122
<MiniCard
101123
onClick={onClick}

app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import { when } from 'vitest-when'
77
import { renderWithProviders } from '../../../__testing-utils__'
88
import { i18n } from '../../../i18n'
99
import { useTrackCreateProtocolRunEvent } from '../../../organisms/Devices/hooks'
10-
import {
11-
useCloseCurrentRun,
12-
useCurrentRunId,
13-
} from '../../../organisms/ProtocolUpload/hooks'
10+
import { useCloseCurrentRun } from '../../../organisms/ProtocolUpload/hooks'
1411
import { useCurrentRunStatus } from '../../../organisms/RunTimeControl/hooks'
1512
import {
1613
getConnectableRobots,
@@ -34,8 +31,11 @@ import { useCreateRunFromProtocol } from '../useCreateRunFromProtocol'
3431
import { useOffsetCandidatesForAnalysis } from '../../ApplyHistoricOffsets/hooks/useOffsetCandidatesForAnalysis'
3532
import { ChooseRobotToRunProtocolSlideout } from '../'
3633
import { useNotifyDataReady } from '../../../resources/useNotifyDataReady'
34+
import { useCurrentRunId } from '../../../resources/runs'
3735

3836
import type { State } from '../../../redux/types'
37+
import type { Runs } from '@opentrons/api-client'
38+
import { UseAllRunsQueryOptions } from '@opentrons/react-api-client/src/runs/useAllRunsQuery'
3939

4040
vi.mock('../../../organisms/Devices/hooks')
4141
vi.mock('../../../organisms/ProtocolUpload/hooks')
@@ -46,6 +46,7 @@ vi.mock('../../../redux/networking')
4646
vi.mock('../useCreateRunFromProtocol')
4747
vi.mock('../../ApplyHistoricOffsets/hooks/useOffsetCandidatesForAnalysis')
4848
vi.mock('../../../resources/useNotifyDataReady')
49+
vi.mock('../../../resources/runs')
4950

5051
const render = (
5152
props: React.ComponentProps<typeof ChooseRobotToRunProtocolSlideout>
@@ -88,7 +89,7 @@ describe('ChooseRobotToRunProtocolSlideout', () => {
8889
isClosingCurrentRun: false,
8990
closeCurrentRun: mockCloseCurrentRun,
9091
})
91-
vi.mocked(useCurrentRunId).mockReturnValue(null)
92+
provideNullCurrentRunIdFor(mockConnectableRobot.ip)
9293
vi.mocked(useCurrentRunStatus).mockReturnValue(null)
9394
when(vi.mocked(useCreateRunFromProtocol))
9495
.calledWith(
@@ -191,6 +192,7 @@ describe('ChooseRobotToRunProtocolSlideout', () => {
191192
{ ...mockConnectableRobot, name: 'otherRobot', ip: 'otherIp' },
192193
mockConnectableRobot,
193194
])
195+
provideNullCurrentRunIdFor('otherIp')
194196
render({
195197
storedProtocolData: storedProtocolDataFixture,
196198
onCloseClick: vi.fn(),
@@ -372,6 +374,7 @@ describe('ChooseRobotToRunProtocolSlideout', () => {
372374
mockConnectableRobot,
373375
{ ...mockConnectableRobot, name: 'otherRobot', ip: 'otherIp' },
374376
])
377+
provideNullCurrentRunIdFor('otherIp')
375378
render({
376379
storedProtocolData: storedProtocolDataFixture,
377380
onCloseClick: vi.fn(),
@@ -387,7 +390,7 @@ describe('ChooseRobotToRunProtocolSlideout', () => {
387390
fireEvent.click(proceedButton)
388391
fireEvent.click(screen.getByRole('button', { name: 'Confirm values' }))
389392
expect(vi.mocked(useCreateRunFromProtocol)).nthCalledWith(
390-
2,
393+
3,
391394
expect.any(Object),
392395
{ hostname: '127.0.0.1' },
393396
[
@@ -450,3 +453,21 @@ describe('ChooseRobotToRunProtocolSlideout', () => {
450453
)
451454
})
452455
})
456+
457+
const provideNullCurrentRunIdFor = (hostname: string): void => {
458+
let once = true
459+
when(vi.mocked(useCurrentRunId))
460+
.calledWith(expect.any(Object), {
461+
hostname,
462+
requestor: undefined,
463+
})
464+
.thenDo(options => {
465+
void (options?.onSuccess != null && once
466+
? options.onSuccess(({
467+
links: { current: null },
468+
} as unknown) as UseAllRunsQueryOptions)
469+
: {})
470+
once = false
471+
return null
472+
})
473+
}

0 commit comments

Comments
 (0)