Skip to content
2 changes: 1 addition & 1 deletion app/src/assets/localization/en/device_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"e_stop_connected": "E-stop successfully connected",
"e_stop_not_connected": "Connect the E-stop to an auxiliary port on the back of the robot.",
"edit_settings": "Edit settings",
"enable_camera_to_run": "Enable the camera to run this protocol",
"enable_camera_to_run": "Enable the camera to start the run",
"enable_status_light": "Enable status light",
"enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.",
"enabled": "Enabled",
Expand Down
41 changes: 35 additions & 6 deletions app/src/organisms/Desktop/Devices/ProtocolRun/ProtocolRunSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { INCOMPATIBLE, INEXACT_MATCH } from '/app/redux/pipettes'
import {
appliedOffsetsToRun,
CAMERA_SETUP_STEP_KEY,
getCameraUsageState,
getMissingSetupSteps,
LABWARE_SETUP_STEP_KEY,
LPC_STEP_KEY,
Expand Down Expand Up @@ -135,6 +136,9 @@ export function ProtocolRunSetup({
robotType,
protocolName,
})
const { enabled: cameraEnabled } = useSelector((state: State) =>
getCameraUsageState(state, runId)
)

const missingSteps = useSelector<State, StepKey[]>(
(state: State): StepKey[] => getMissingSetupSteps(state, runId)
Expand Down Expand Up @@ -248,6 +252,7 @@ export function ProtocolRunSetup({
if (robot == null) {
return null
}

const StepDetailMap: Record<
StepKey,
{
Expand Down Expand Up @@ -288,6 +293,7 @@ export function ProtocolRunSetup({
incompleteText: t('calibration_needed'),
missingHardwareText: t('action_needed'),
incompleteElement: null,
disabledHardware: false,
},
},
[MODULE_SETUP_STEP_KEY]: {
Expand Down Expand Up @@ -316,6 +322,7 @@ export function ProtocolRunSetup({
? t('modules_and_fixtures_ready')
: t('modules_ready'),
incompleteText: t('action_needed'),
disabledHardware: false,
missingHardware: isMissingModule || isFixtureMismatch,
missingHardwareText: t('action_needed'),
incompleteElement: null,
Expand Down Expand Up @@ -421,6 +428,9 @@ export function ProtocolRunSetup({
completeText: t('camera_enabled'),
incompleteText: t('check_preferences'),
incompleteElement: null,
disabledHardware: !cameraEnabled,
missingHardware: !!storageInfo?.isImageStorageLow,
missingHardwareText: t('check_preferences'),
},
},
}
Expand Down Expand Up @@ -511,9 +521,13 @@ interface NoHardwareRequiredStepCompletion {
}

interface HardwareRequiredStepCompletion {
stepKey: typeof ROBOT_CALIBRATION_STEP_KEY | typeof MODULE_SETUP_STEP_KEY
stepKey:
| typeof ROBOT_CALIBRATION_STEP_KEY
| typeof MODULE_SETUP_STEP_KEY
| typeof CAMERA_SETUP_STEP_KEY
complete: boolean
missingHardware: boolean
disabledHardware: boolean
incompleteText: string | null
incompleteElement: JSX.Element | null
completeText: string
Expand All @@ -528,7 +542,8 @@ const stepRequiresHW = (
props: StepRightElementProps
): props is HardwareRequiredStepCompletion =>
props.stepKey === ROBOT_CALIBRATION_STEP_KEY ||
props.stepKey === MODULE_SETUP_STEP_KEY
props.stepKey === MODULE_SETUP_STEP_KEY ||
props.stepKey === CAMERA_SETUP_STEP_KEY

function StepRightElement(props: StepRightElementProps): JSX.Element | null {
if (props.complete) {
Expand All @@ -555,23 +570,37 @@ function StepRightElement(props: StepRightElementProps): JSX.Element | null {
</StyledText>
</Flex>
)
} else if (stepRequiresHW(props) && props.missingHardware) {
} else if (stepRequiresHW(props)) {
return (
<Flex flexDirection={DIRECTION_ROW} alignItems={ALIGN_CENTER}>
<Icon
size="1rem"
color={COLORS.yellow60}
color={
props.disabledHardware
? COLORS.red60
: props.missingHardware
? COLORS.yellow60
: COLORS.grey60
}
marginRight={SPACING.spacing8}
name="alert-circle"
id={`RunSetupCard_${props.stepKey}_missingHardwareIcon`}
/>
<StyledText
desktopStyle="bodyDefaultSemiBold"
color={COLORS.yellow60}
color={
props.disabledHardware
? COLORS.red60
: props.missingHardware
? COLORS.yellow60
: COLORS.grey60
}
marginRight={SPACING.spacing16}
id={`RunSetupCard_${props.stepKey}_missingHardwareText`}
>
{props.missingHardwareText}
{props.missingHardware
? props.missingHardwareText
: props.incompleteText}
</StyledText>
</Flex>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ describe('SetupCamera', () => {
render(mockProps)

screen.getByText('Camera is required.')
screen.getByText('Enable the camera to run this protocol.')
screen.getByText('Enable the camera to start the run.')
})

it('does not render SetupRunCameraUsage when camera is disabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useIsFlex, useRobot } from '/app/redux-resources/robots'
import { useRequiredSetupStepsInOrder } from '/app/redux-resources/runs'
import { mockConnectedRobot } from '/app/redux/discovery/__fixtures__'
import {
getCameraUsageState,
getMissingSetupSteps,
selectAreOffsetsApplied,
selectIsAnyNecessaryDefaultOffsetMissing,
Expand Down Expand Up @@ -114,6 +115,11 @@ describe('ProtocolRunSetup', () => {
when(vi.mocked(useProtocolAnalysisErrors)).calledWith(RUN_ID).thenReturn({
analysisErrors: null,
})
vi.mocked(getCameraUsageState).mockReturnValue({
enabled: false,
recoveryEnabled: true,
liveStreamEnabled: true,
})
when(vi.mocked(useStoredProtocolAnalysis))
.calledWith(RUN_ID)
.thenReturn({
Expand Down
1 change: 1 addition & 0 deletions app/src/organisms/Desktop/Devices/RobotCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ function AttachedDevices(props: { robotName: string }): JSX.Element | null {
const { robotName } = props
const { t } = useTranslation('devices_landing')
const { data } = useCamera()

return data?.cameraEnabled ? (
<Flex
flexDirection={DIRECTION_COLUMN}
Expand Down
Loading