@@ -174,7 +174,6 @@ export function ProtocolRunHeader({
174
174
const [ pipettesWithTip , setPipettesWithTip ] = React . useState <
175
175
PipettesWithTip [ ]
176
176
> ( [ ] )
177
- const [ closeTerminalBanner , setCloseTerminalBanner ] = React . useState ( false )
178
177
const isResetRunLoadingRef = React . useRef ( false )
179
178
const { data : runRecord } = useNotifyRunQuery ( runId , { staleTime : Infinity } )
180
179
const highestPriorityError =
@@ -200,7 +199,7 @@ export function ProtocolRunHeader({
200
199
const { data : doorStatus } = useDoorQuery ( {
201
200
refetchInterval : EQUIPMENT_POLL_MS ,
202
201
} )
203
- let isDoorOpen = false
202
+ let isDoorOpen : boolean
204
203
if ( isFlex ) {
205
204
isDoorOpen = doorStatus ?. data . status === 'open'
206
205
} else if ( ! isFlex && Boolean ( doorSafetySetting ?. value ) ) {
@@ -248,7 +247,9 @@ export function ProtocolRunHeader({
248
247
}
249
248
} , [ protocolData , isRobotViewable , history ] )
250
249
250
+ // Side effects dependent on the current run state.
251
251
React . useEffect ( ( ) => {
252
+ // After a user-initiated stopped run, close the run current run automatically.
252
253
if ( runStatus === RUN_STATUS_STOPPED && isRunCurrent && runId != null ) {
253
254
trackProtocolRunEvent ( {
254
255
name : ANALYTICS_PROTOCOL_RUN_FINISH ,
@@ -260,12 +261,6 @@ export function ProtocolRunHeader({
260
261
}
261
262
} , [ runStatus , isRunCurrent , runId , closeCurrentRun ] )
262
263
263
- React . useEffect ( ( ) => {
264
- if ( runStatus === RUN_STATUS_IDLE ) {
265
- setCloseTerminalBanner ( false )
266
- }
267
- } , [ runStatus ] )
268
-
269
264
const startedAtTimestamp =
270
265
startedAt != null ? formatTimestamp ( startedAt ) : EMPTY_TIMESTAMP
271
266
@@ -310,7 +305,6 @@ export function ProtocolRunHeader({
310
305
properties : robotAnalyticsData ?? undefined ,
311
306
} )
312
307
closeCurrentRun ( )
313
- setCloseTerminalBanner ( true )
314
308
}
315
309
316
310
return (
@@ -375,7 +369,7 @@ export function ProtocolRunHeader({
375
369
CANCELLABLE_STATUSES . includes ( runStatus ) ? (
376
370
< Banner type = "warning" > { t ( 'shared:close_robot_door' ) } </ Banner >
377
371
) : null }
378
- { mostRecentRunId === runId && ! closeTerminalBanner ? (
372
+ { mostRecentRunId === runId ? (
379
373
< TerminalRunBanner
380
374
{ ...{
381
375
runStatus,
@@ -385,6 +379,7 @@ export function ProtocolRunHeader({
385
379
highestPriorityError,
386
380
} }
387
381
isResetRunLoading = { isResetRunLoadingRef . current }
382
+ isRunCurrent = { isRunCurrent }
388
383
/>
389
384
) : null }
390
385
{ mostRecentRunId === runId &&
@@ -479,7 +474,9 @@ export function ProtocolRunHeader({
479
474
setShowDropTipWizard ( false )
480
475
setPipettesWithTip ( prevPipettesWithTip => {
481
476
const pipettesWithTip = prevPipettesWithTip . slice ( 1 ) ?? [ ]
482
- if ( pipettesWithTip . length === 0 ) closeCurrentRun ( )
477
+ if ( pipettesWithTip . length === 0 ) {
478
+ closeCurrentRun ( )
479
+ }
483
480
return pipettesWithTip
484
481
} )
485
482
} }
@@ -570,6 +567,7 @@ interface ActionButtonProps {
570
567
isResetRunLoadingRef : React . MutableRefObject < boolean >
571
568
}
572
569
570
+ // TODO(jh, 04-22-2024): Refactor switch cases into separate factories to increase readability and testability.
573
571
function ActionButton ( props : ActionButtonProps ) : JSX . Element {
574
572
const {
575
573
runId,
@@ -613,9 +611,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element {
613
611
robotName ,
614
612
runId
615
613
)
616
- const [ showIsShakingModal , setShowIsShakingModal ] = React . useState < boolean > (
617
- false
618
- )
614
+ const [ showIsShakingModal , setShowIsShakingModal ] = React . useState ( false )
619
615
const isSetupComplete =
620
616
isCalibrationComplete &&
621
617
isModuleCalibrationComplete &&
@@ -804,12 +800,14 @@ function ActionButton(props: ActionButtonProps): JSX.Element {
804
800
)
805
801
}
806
802
803
+ // TODO(jh 04-24-2024): Split TerminalRunBanner into a RunSuccessBanner and RunFailedBanner.
807
804
interface TerminalRunProps {
808
805
runStatus : RunStatus | null
809
806
handleClearClick : ( ) => void
810
807
isClosingCurrentRun : boolean
811
808
setShowRunFailedModal : ( showRunFailedModal : boolean ) => void
812
809
isResetRunLoading : boolean
810
+ isRunCurrent : boolean
813
811
highestPriorityError ?: RunError | null
814
812
}
815
813
function TerminalRunBanner ( props : TerminalRunProps ) : JSX . Element | null {
@@ -820,51 +818,64 @@ function TerminalRunBanner(props: TerminalRunProps): JSX.Element | null {
820
818
setShowRunFailedModal,
821
819
highestPriorityError,
822
820
isResetRunLoading,
821
+ isRunCurrent,
823
822
} = props
824
823
const { t } = useTranslation ( 'run_details' )
825
824
826
- const handleClick = ( ) : void => {
825
+ const handleRunSuccessClick = ( ) : void => {
826
+ handleClearClick ( )
827
+ }
828
+
829
+ const handleFailedRunClick = ( ) : void => {
827
830
handleClearClick ( )
828
831
setShowRunFailedModal ( true )
829
832
}
830
833
831
- if (
832
- isResetRunLoading === false &&
833
- ( runStatus === RUN_STATUS_FAILED || runStatus === RUN_STATUS_SUCCEEDED )
834
- ) {
834
+ const buildSuccessBanner = ( ) : JSX . Element => {
835
835
return (
836
- < >
837
- { runStatus === RUN_STATUS_SUCCEEDED ? (
838
- < Banner
839
- type = "success"
840
- onCloseClick = { handleClearClick }
841
- isCloseActionLoading = { isClosingCurrentRun }
842
- >
843
- < Flex justifyContent = { JUSTIFY_SPACE_BETWEEN } width = "100%" >
844
- { t ( 'run_completed' ) }
845
- </ Flex >
846
- </ Banner >
847
- ) : (
848
- < Banner type = "error" >
849
- < Flex justifyContent = { JUSTIFY_SPACE_BETWEEN } width = "100%" >
850
- < StyledText >
851
- { t ( 'error_info' , {
852
- errorType : highestPriorityError ?. errorType ,
853
- errorCode : highestPriorityError ?. errorCode ,
854
- } ) }
855
- </ StyledText >
836
+ < Banner
837
+ type = "success"
838
+ onCloseClick = { handleRunSuccessClick }
839
+ isCloseActionLoading = { isClosingCurrentRun }
840
+ >
841
+ < Flex justifyContent = { JUSTIFY_SPACE_BETWEEN } width = "100%" >
842
+ { t ( 'run_completed' ) }
843
+ </ Flex >
844
+ </ Banner >
845
+ )
846
+ }
856
847
857
- < LinkButton
858
- onClick = { handleClick }
859
- textDecoration = { TYPOGRAPHY . textDecorationUnderline }
860
- >
861
- { t ( 'view_error' ) }
862
- </ LinkButton >
863
- </ Flex >
864
- </ Banner >
865
- ) }
866
- </ >
848
+ const buildErrorBanner = ( ) : JSX . Element => {
849
+ return (
850
+ < Banner type = "error" >
851
+ < Flex justifyContent = { JUSTIFY_SPACE_BETWEEN } width = "100%" >
852
+ < StyledText >
853
+ { t ( 'error_info' , {
854
+ errorType : highestPriorityError ?. errorType ,
855
+ errorCode : highestPriorityError ?. errorCode ,
856
+ } ) }
857
+ </ StyledText >
858
+
859
+ < LinkButton
860
+ onClick = { handleFailedRunClick }
861
+ textDecoration = { TYPOGRAPHY . textDecorationUnderline }
862
+ >
863
+ { t ( 'view_error' ) }
864
+ </ LinkButton >
865
+ </ Flex >
866
+ </ Banner >
867
867
)
868
868
}
869
- return null
869
+
870
+ if (
871
+ runStatus === RUN_STATUS_SUCCEEDED &&
872
+ isRunCurrent &&
873
+ ! isResetRunLoading
874
+ ) {
875
+ return buildSuccessBanner ( )
876
+ } else if ( runStatus === RUN_STATUS_FAILED && ! isResetRunLoading ) {
877
+ return buildErrorBanner ( )
878
+ } else {
879
+ return null
880
+ }
870
881
}
0 commit comments