From b53815615b6653ff32cc4f3b78f1339a0d3a7c71 Mon Sep 17 00:00:00 2001 From: Sarah Breen Date: Thu, 21 Sep 2023 13:23:15 -0400 Subject: [PATCH] fix(app): disable instrument card controls when run is active (#13601) fix RQA-1575, RQA-1515, RQA-1380 --- .../Devices/InstrumentsAndModules.tsx | 3 ++ .../PipetteCard/PipetteOverflowMenu.tsx | 5 ++ .../__tests__/PipetteCard.test.tsx | 11 +++++ .../__tests__/PipetteOverflowMenu.test.tsx | 1 + .../organisms/Devices/PipetteCard/index.tsx | 3 ++ .../RobotUpdateProgressModal.tsx | 48 +++++++++++-------- .../__tests__/GripperCard.test.tsx | 5 ++ app/src/organisms/GripperCard/index.tsx | 8 ++-- .../organisms/ModuleWizardFlows/Success.tsx | 17 +++++-- 9 files changed, 72 insertions(+), 29 deletions(-) diff --git a/app/src/organisms/Devices/InstrumentsAndModules.tsx b/app/src/organisms/Devices/InstrumentsAndModules.tsx index 86ad023f1ff..bb700732a26 100644 --- a/app/src/organisms/Devices/InstrumentsAndModules.tsx +++ b/app/src/organisms/Devices/InstrumentsAndModules.tsx @@ -213,6 +213,7 @@ export function InstrumentsAndModules({ pipetteIs96Channel={is96ChannelAttached} pipetteIsBad={badLeftPipette != null} updatePipette={() => setSubsystemToUpdate('pipette_left')} + isRunActive={currentRunId != null && !isRunTerminal} /> {isOT3 && ( )} {leftColumnModules.map((module, index) => ( @@ -263,6 +265,7 @@ export function InstrumentsAndModules({ pipetteIs96Channel={false} pipetteIsBad={badRightPipette != null} updatePipette={() => setSubsystemToUpdate('pipette_right')} + isRunActive={currentRunId != null && !isRunTerminal} /> )} {rightColumnModules.map((module, index) => ( diff --git a/app/src/organisms/Devices/PipetteCard/PipetteOverflowMenu.tsx b/app/src/organisms/Devices/PipetteCard/PipetteOverflowMenu.tsx index ee1399ea160..6107721a730 100644 --- a/app/src/organisms/Devices/PipetteCard/PipetteOverflowMenu.tsx +++ b/app/src/organisms/Devices/PipetteCard/PipetteOverflowMenu.tsx @@ -32,6 +32,7 @@ interface PipetteOverflowMenuProps { handleAboutSlideout: () => void handleSettingsSlideout: () => void isPipetteCalibrated: boolean + isRunActive: boolean } export const PipetteOverflowMenu = ( @@ -47,6 +48,7 @@ export const PipetteOverflowMenu = ( handleAboutSlideout, handleSettingsSlideout, isPipetteCalibrated, + isRunActive, } = props const pipetteName = @@ -72,6 +74,7 @@ export const PipetteOverflowMenu = ( handleChangePipette()} + disabled={isRunActive} data-testid={`pipetteOverflowMenu_attach_pipette_btn_${String( pipetteDisplayName )}_${mount}`} @@ -84,6 +87,7 @@ export const PipetteOverflowMenu = ( handleCalibrate()} + disabled={isRunActive} data-testid={`pipetteOverflowMenu_calibrate_offset_btn_${pipetteDisplayName}_${mount}`} > {t( @@ -96,6 +100,7 @@ export const PipetteOverflowMenu = ( handleChangePipette()} + disabled={isRunActive} data-testid={`pipetteOverflowMenu_detach_pipette_btn_${String( pipetteDisplayName )}_${mount}`} diff --git a/app/src/organisms/Devices/PipetteCard/__tests__/PipetteCard.test.tsx b/app/src/organisms/Devices/PipetteCard/__tests__/PipetteCard.test.tsx index 4ec2b1b36d2..2e68851c5c5 100644 --- a/app/src/organisms/Devices/PipetteCard/__tests__/PipetteCard.test.tsx +++ b/app/src/organisms/Devices/PipetteCard/__tests__/PipetteCard.test.tsx @@ -88,6 +88,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } when(mockUseIsOT3).calledWith(mockRobotName).mockReturnValue(false) when(mockAboutPipettesSlideout).mockReturnValue( @@ -131,6 +132,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('left Mount') @@ -146,6 +148,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText, getByRole } = render(props) getByText('Both Mounts') @@ -166,6 +169,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('right Mount') @@ -180,6 +184,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('right Mount') @@ -194,6 +199,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('left Mount') @@ -209,6 +215,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { queryByText } = render(props) expect(queryByText('Calibrate now')).toBeNull() @@ -223,6 +230,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('Calibrate now') @@ -236,6 +244,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: false, updatePipette: jest.fn(), + isRunActive: false, } const { getByRole, getByText, queryByText } = render(props) @@ -258,6 +267,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: true, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('Right mount') @@ -278,6 +288,7 @@ describe('PipetteCard', () => { isPipetteCalibrated: false, pipetteIsBad: true, updatePipette: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('Right mount') diff --git a/app/src/organisms/Devices/PipetteCard/__tests__/PipetteOverflowMenu.test.tsx b/app/src/organisms/Devices/PipetteCard/__tests__/PipetteOverflowMenu.test.tsx index 00d6a6d2355..7a534b4956e 100644 --- a/app/src/organisms/Devices/PipetteCard/__tests__/PipetteOverflowMenu.test.tsx +++ b/app/src/organisms/Devices/PipetteCard/__tests__/PipetteOverflowMenu.test.tsx @@ -45,6 +45,7 @@ describe('PipetteOverflowMenu', () => { handleAboutSlideout: jest.fn(), handleSettingsSlideout: jest.fn(), isPipetteCalibrated: false, + isRunActive: false, } }) afterEach(() => { diff --git a/app/src/organisms/Devices/PipetteCard/index.tsx b/app/src/organisms/Devices/PipetteCard/index.tsx index 6cb41f0560b..ff44bcf3589 100644 --- a/app/src/organisms/Devices/PipetteCard/index.tsx +++ b/app/src/organisms/Devices/PipetteCard/index.tsx @@ -62,6 +62,7 @@ interface PipetteCardProps { pipetteIsBad: boolean updatePipette: () => void pipetteId?: AttachedPipette['id'] | null + isRunActive: boolean } const BANNER_LINK_STYLE = css` text-decoration: underline; @@ -92,6 +93,7 @@ export const PipetteCard = (props: PipetteCardProps): JSX.Element => { pipetteIs96Channel, pipetteIsBad, updatePipette, + isRunActive, } = props const { menuOverlay, @@ -351,6 +353,7 @@ export const PipetteCard = (props: PipetteCardProps): JSX.Element => { handleCalibrate={handleCalibrate} isPipetteCalibrated={isPipetteCalibrated} pipetteSettings={settings} + isRunActive={isRunActive} /> {menuOverlay} diff --git a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/RobotUpdateProgressModal.tsx b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/RobotUpdateProgressModal.tsx index a051f2af5d5..31ca9616b58 100644 --- a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/RobotUpdateProgressModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/RobotUpdateProgressModal.tsx @@ -42,11 +42,16 @@ function SuccessOrError({ errorMessage }: SuccessOrErrorProps): JSX.Element { let renderedImg: JSX.Element if (!errorMessage) renderedImg = ( - {IMAGE_ALT} + {IMAGE_ALT} ) else renderedImg = ( - + ) return ( @@ -104,6 +109,7 @@ function RobotUpdateProgressFooter({ onClick={installUpdate} marginRight={SPACING.spacing8} css={FOOTER_BUTTON_STYLE} + border="none" > {t('try_again')} @@ -218,26 +224,26 @@ export function RobotUpdateProgressModal({ ) : null } > - - {completedUpdating ? ( + {completedUpdating ? ( + - ) : ( - <> - {modalBodyText} - - - {t('do_not_turn_off')} - - - )} - + + ) : ( + + {modalBodyText} + + + {t('do_not_turn_off')} + + + )} ) } diff --git a/app/src/organisms/GripperCard/__tests__/GripperCard.test.tsx b/app/src/organisms/GripperCard/__tests__/GripperCard.test.tsx index 76ab0d39601..2edf2484a56 100644 --- a/app/src/organisms/GripperCard/__tests__/GripperCard.test.tsx +++ b/app/src/organisms/GripperCard/__tests__/GripperCard.test.tsx @@ -46,6 +46,7 @@ describe('GripperCard', () => { } as GripperData, isCalibrated: true, setSubsystemToUpdate: jest.fn(), + isRunActive: false, } mockGripperWizardFlows.mockReturnValue(<>wizard flow launched) mockAboutGripperSlideout.mockReturnValue(<>about gripper) @@ -87,6 +88,7 @@ describe('GripperCard', () => { } as GripperData, isCalibrated: false, setSubsystemToUpdate: jest.fn(), + isRunActive: false, } const { getByText } = render(props) @@ -127,6 +129,7 @@ describe('GripperCard', () => { attachedGripper: null, isCalibrated: false, setSubsystemToUpdate: jest.fn(), + isRunActive: false, } const { getByText, getByRole } = render(props) const overflowButton = getByRole('button', { @@ -144,6 +147,7 @@ describe('GripperCard', () => { } as any, isCalibrated: false, setSubsystemToUpdate: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('Extension mount') @@ -162,6 +166,7 @@ describe('GripperCard', () => { } as any, isCalibrated: true, setSubsystemToUpdate: jest.fn(), + isRunActive: false, } const { getByText } = render(props) getByText('Extension mount') diff --git a/app/src/organisms/GripperCard/index.tsx b/app/src/organisms/GripperCard/index.tsx index 0c900e88576..084e7d7198d 100644 --- a/app/src/organisms/GripperCard/index.tsx +++ b/app/src/organisms/GripperCard/index.tsx @@ -17,6 +17,7 @@ interface GripperCardProps { attachedGripper: GripperData | BadGripper | null isCalibrated: boolean setSubsystemToUpdate: (subsystem: Subsystem | null) => void + isRunActive: boolean } const BANNER_LINK_CSS = css` text-decoration: underline; @@ -40,6 +41,7 @@ export function GripperCard({ attachedGripper, isCalibrated, setSubsystemToUpdate, + isRunActive, }: GripperCardProps): JSX.Element { const { t, i18n } = useTranslation(['device_details', 'shared']) const [ @@ -73,7 +75,7 @@ export function GripperCard({ ? [ { label: t('attach_gripper'), - disabled: attachedGripper != null, + disabled: attachedGripper != null || isRunActive, onClick: handleAttach, }, ] @@ -83,12 +85,12 @@ export function GripperCard({ attachedGripper.data.calibratedOffset?.last_modified != null ? t('recalibrate_gripper') : t('calibrate_gripper'), - disabled: attachedGripper == null, + disabled: attachedGripper == null || isRunActive, onClick: handleCalibrate, }, { label: t('detach_gripper'), - disabled: attachedGripper == null, + disabled: attachedGripper == null || isRunActive, onClick: handleDetach, }, { diff --git a/app/src/organisms/ModuleWizardFlows/Success.tsx b/app/src/organisms/ModuleWizardFlows/Success.tsx index 2e0847f02f2..16b8273214f 100644 --- a/app/src/organisms/ModuleWizardFlows/Success.tsx +++ b/app/src/organisms/ModuleWizardFlows/Success.tsx @@ -4,11 +4,12 @@ import { css } from 'styled-components' import { getModuleDisplayName } from '@opentrons/shared-data' import { COLORS, + JUSTIFY_FLEX_END, PrimaryButton, RESPONSIVENESS, TYPOGRAPHY, } from '@opentrons/components' - +import { SmallButton } from '../../atoms/buttons' import { SimpleWizardBody } from '../../molecules/SimpleWizardBody' import type { ModuleCalibrationWizardStepProps } from './types' @@ -24,13 +25,20 @@ export const BODY_STYLE = css` export const Success = ( props: ModuleCalibrationWizardStepProps ): JSX.Element | null => { - const { proceed, attachedModule, isRobotMoving } = props + const { proceed, attachedModule, isRobotMoving, isOnDevice } = props const { t } = useTranslation('module_wizard_flows') const moduleDisplayName = getModuleDisplayName(attachedModule.moduleModel) const handleOnClick = (): void => { proceed() } + const button = isOnDevice ? ( + + ) : ( + + {t('exit')} + + ) return ( - - {t('exit')} - + {button} ) }