Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): wire up module calibration to backend #13449

Merged
merged 14 commits into from
Sep 1, 2023
Merged
1 change: 0 additions & 1 deletion app/src/assets/localization/en/app_settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"__dev_internal__enableExtendedHardware": "Enable Extended Hardware",
"__dev_internal__enableModuleCalibration": "Enable Module Calibration",
"__dev_internal__lpcWithProbe": "Golden Tip LPC",
"add_folder_button": "Add labware source folder",
"add_ip_button": "Add",
Expand Down
9 changes: 8 additions & 1 deletion app/src/assets/localization/en/module_wizard_flows.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
"calibration_adapter_temperature": "Calibration Adapter",
"calibration_adapter_thermocycler": "Calibration Adapter",
"checking_firmware": "Checking {{module}} firmware",
"complete_calibration": "Complete calibration",
"confirm_location": "Confirm location",
"confirm_placement": "Confirm placement",
"detach_probe": "Remove pipette probe",
"detach_probe_description": "Unlock the pipette calibration probe, remove it from the nozzle, and return it to its storage location.",
"error_during_calibration": "Error during calibration",
"exit": "Exit",
"firmware_updated": "{{module}} firmware updated!",
"get_started": "<block>To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.</block><block>The calibration adapter came with your module. The pipette probe came with your Flex pipette.</block>",
Expand All @@ -20,14 +24,17 @@
"install_probe": "Take the calibration probe from its storage location. Ensure its collar is unlocked. Push the pipette ejector up and press the probe firmly onto the pipette nozzle. Twist the collar to lock the probe. Test that the probe is secure by gently pulling it back and forth.",
"module_calibration": "Module calibration",
"module_calibrating": "Stand back, {{moduleName}} is calibrating",
"module_calibration_failed": "The module calibration could not be completed. Contact customer support for assistance.",
"module_secured": "The module must be fully secured in its caddy and secured in the deck slot.",
"move_gantry_to_front": "Move gantry to front",
"next": "Next",
"pipette_probe": "Pipette Probe",
"place_adapter": "Place calibration adapter in {{module}}",
"place_flush": "Place the adapter flush on top of the module.",
"recalibrate": "Recalibrate",
"stand_back": "Stand back, calibration in progress",
"successfully_calibrated": "{{module}} successfully calibrated",
"select_location": "Select module location",
"select_the_slot": "Select the slot where you installed the {{module}} on the deck map to the right. The location must be correct for successful calibration."
"select_the_slot": "Select the slot where you installed the {{module}} on the deck map to the right. The location must be correct for successful calibration.",
"start_setup": "Start setup"
}
2 changes: 1 addition & 1 deletion app/src/assets/localization/en/run_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"start_time": "Start Time",
"start": "Start",
"status_blocked-by-open-door": "Paused - door open",
"status_failed": "Completed",
"status_failed": "Failed",
"status_finishing": "Finishing",
"status_idle": "Not started",
"status_pause-requested": "Pause requested",
Expand Down
2 changes: 1 addition & 1 deletion app/src/molecules/WizardHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { StepMeter } from '../../atoms/StepMeter'

interface WizardHeaderProps {
title: string
onExit?: React.MouseEventHandler | null
onExit?: (() => void) | null
totalSteps?: number
currentStep?: number | null
exitDisabled?: boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ describe('ProtocolRunHeader', () => {
const [{ getByText }] = render()

const button = getByText('Run again')
getByText('Completed')
getByText('Failed')
getByText(formatTimestamp(COMPLETED_AT))
fireEvent.click(button)
expect(mockTrackProtocolRunEvent).toBeCalledWith({
Expand Down
6 changes: 5 additions & 1 deletion app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface BeforeBeginningProps extends GripperWizardStepProps {
unknown
>
isCreateLoading: boolean
createdMaintenanceRunId: string | null
}

export const BeforeBeginning = (
Expand All @@ -70,10 +71,13 @@ export const BeforeBeginning = (
errorMessage,
maintenanceRunId,
setErrorMessage,
createdMaintenanceRunId,
} = props
const { t } = useTranslation(['gripper_wizard_flows', 'shared'])
React.useEffect(() => {
createMaintenanceRun({})
if (createdMaintenanceRunId == null) {
createMaintenanceRun({})
}
}, [])

const commandsOnProceed: CreateCommand[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ describe('BeforeBeginning', () => {
isRobotMoving: false,
setErrorMessage: jest.fn(),
errorMessage: null,
createdMaintenanceRunId: null,
}
// mockNeedHelpLink.mockReturnValue(<div>mock need help link</div>)
mockInProgressModal.mockReturnValue(<div>mock in progress</div>)
Expand Down
1 change: 1 addition & 0 deletions app/src/organisms/GripperWizardFlows/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ export const GripperWizard = (
{...currentStep}
{...sharedProps}
createMaintenanceRun={createMaintenanceRun}
createdMaintenanceRunId={createdMaintenanceRunId}
/>
)
} else if (currentStep.section === SECTIONS.MOVE_PIN) {
Expand Down
16 changes: 9 additions & 7 deletions app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Flex, POSITION_RELATIVE } from '@opentrons/components'

import { MenuList } from '../../atoms/MenuList'
import { MenuItem } from '../../atoms/MenuList/MenuItem'
import { useFeatureFlag } from '../../redux/config'
import { useCurrentRunId } from '../ProtocolUpload/hooks'
import {
useIsOT3,
Expand Down Expand Up @@ -43,7 +42,7 @@ export const ModuleOverflowMenu = (
isLoadedInRun,
} = props

const { t } = useTranslation('module_wizard_flows')
const { t, i18n } = useTranslation('module_wizard_flows')

const currentRunId = useCurrentRunId()
const { isRunTerminal, isRunStill } = useRunStatuses()
Expand All @@ -52,8 +51,6 @@ export const ModuleOverflowMenu = (
const isIncompatibleWithOT3 =
isOT3 && module.moduleModel === 'thermocyclerModuleV1'

const enableModuleCalibration = useFeatureFlag('enableModuleCalibration')

let isDisabled: boolean = false
if (runId != null && isLoadedInRun) {
isDisabled = !isRunStill
Expand All @@ -78,9 +75,14 @@ export const ModuleOverflowMenu = (
return (
<Flex position={POSITION_RELATIVE}>
<MenuList>
{enableModuleCalibration ? (
<MenuItem onClick={handleCalibrateClick}>{t('calibrate')}</MenuItem>
) : null}
<MenuItem onClick={handleCalibrateClick}>
{i18n.format(
module.moduleOffset?.last_modified != null
? t('recalibrate')
: t('calibrate'),
'capitalize'
)}
</MenuItem>
{menuOverflowItemsByModuleType[module.moduleType].map(
(item: any, index: number) => {
return (
Expand Down
72 changes: 46 additions & 26 deletions app/src/organisms/ModuleWizardFlows/AttachProbe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ import attachProbe1 from '../../assets/videos/pipette-wizard-flows/Pipette_Attac
import attachProbe8 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_8.webm'
import attachProbe96 from '../../assets/videos/pipette-wizard-flows/Pipette_Attach_Probe_96.webm'
import { Trans, useTranslation } from 'react-i18next'
import { THERMOCYCLER_MODULE_MODELS } from '@opentrons/shared-data/js/constants'
import {
LEFT,
THERMOCYCLER_MODULE_MODELS,
} from '@opentrons/shared-data/js/constants'
import { getModuleDisplayName } from '@opentrons/shared-data/js/modules'
import { InProgressModal } from '../../molecules/InProgressModal/InProgressModal'
import {
Flex,
RESPONSIVENESS,
SPACING,
TYPOGRAPHY,
COLORS,
} from '@opentrons/components'

import { StyledText } from '../../atoms/text'
import { GenericWizardTile } from '../../molecules/GenericWizardTile'
import { SimpleWizardBody } from '../../molecules/SimpleWizardBody'

import type { ModuleCalibrationWizardStepProps } from './types'
interface AttachProbeProps extends ModuleCalibrationWizardStepProps {
isExiting: boolean
adapterId: string | null
}

const IN_PROGRESS_STYLE = css`
Expand All @@ -50,10 +52,12 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => {
const {
proceed,
goBack,
chainRunCommands,
setErrorMessage,
adapterId,
isRobotMoving,
attachedModule,
attachedPipette,
errorMessage,
isExiting,
isOnDevice,
slotName,
Expand Down Expand Up @@ -168,34 +172,50 @@ export const AttachProbe = (props: AttachProbeProps): JSX.Element | null => {
<StyledText css={BODY_STYLE}>{t('install_probe')}</StyledText>
)

const handleBeginCalibration = (): void => {
if (adapterId == null) {
setErrorMessage('calibration adapter has not been loaded yet')
return
}
chainRunCommands?.(
[
{
commandType: 'home' as const,
params: {
axes: attachedPipette.mount === LEFT ? ['leftZ'] : ['rightZ'],
},
},
{
commandType: 'calibration/calibrateModule',
params: {
moduleId: attachedModule.id,
labwareId: adapterId,
mount: attachedPipette.mount,
},
},
{
commandType: 'calibration/moveToMaintenancePosition' as const,
params: {
mount: attachedPipette.mount,
},
},
],
false
)
.then(() => proceed())
.catch((e: Error) =>
setErrorMessage(`error starting module calibration: ${e.message}`)
)
}

// TODO: add calibration loading screen and error screen
return errorMessage != null ? (
<SimpleWizardBody
Comment on lines -172 to -173
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved rendering the error to the orchestration component, rather than having each sub component have to worry about rendering error content

isSuccess={false}
iconColor={COLORS.errorEnabled}
header={t('shared:error_encountered')}
subHeader={
<Trans
t={t}
i18nKey={'return_probe_error'}
values={{ error: errorMessage }}
components={{
block: <StyledText as="p" />,
bold: (
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold} />
),
}}
/>
}
/>
) : (
return (
<GenericWizardTile
header={i18n.format(t('attach_probe'), 'capitalize')}
// TODO: make sure this is the right animation
rightHandBody={pipetteAttachProbeVid}
bodyText={bodyText}
proceedButtonText={t('begin_calibration')}
proceed={proceed}
proceed={handleBeginCalibration}
back={goBack}
/>
)
Expand Down
21 changes: 7 additions & 14 deletions app/src/organisms/ModuleWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import {
import { getModuleDisplayName } from '@opentrons/shared-data'
import { StyledText } from '../../atoms/text'
import { GenericWizardTile } from '../../molecules/GenericWizardTile'
import { SimpleWizardBody } from '../../molecules/SimpleWizardBody'
import { WizardRequiredEquipmentList } from '../../molecules/WizardRequiredEquipmentList'
import { COLORS } from '@opentrons/components'
import type {
CreateMaintenanceRunData,
MaintenanceRun,
Expand All @@ -27,7 +25,7 @@ interface BeforeBeginningProps extends ModuleCalibrationWizardStepProps {
unknown
>
isCreateLoading: boolean
errorMessage: string | null
createdMaintenanceRunId: string | null
}

export const BeforeBeginning = (
Expand All @@ -39,11 +37,13 @@ export const BeforeBeginning = (
isCreateLoading,
attachedModule,
maintenanceRunId,
errorMessage,
createdMaintenanceRunId,
} = props
const { t } = useTranslation(['module_wizard_flows', 'shared'])
React.useEffect(() => {
createMaintenanceRun({})
if (createdMaintenanceRunId == null) {
createMaintenanceRun({})
}
}, [])
const moduleDisplayName = getModuleDisplayName(attachedModule.moduleModel)

Expand Down Expand Up @@ -82,14 +82,7 @@ export const BeforeBeginning = (
{ loadName: adapterLoadname, displayName: t(adapterDisplaynameKey) },
]

return errorMessage != null ? (
<SimpleWizardBody
isSuccess={false}
iconColor={COLORS.errorEnabled}
header={t('shared:error_encountered')}
subHeader={errorMessage}
/>
) : (
return (
<GenericWizardTile
header={t('calibration', { module: moduleDisplayName })}
rightHandBody={
Expand All @@ -103,7 +96,7 @@ export const BeforeBeginning = (
components={{ block: <StyledText as="p" /> }}
/>
}
proceedButtonText={t('move_gantry_to_front')}
proceedButtonText={t('start_setup')}
proceedIsDisabled={isCreateLoading || maintenanceRunId == null}
proceed={proceed}
/>
Expand Down
Loading