Skip to content

Commit

Permalink
fix(app): fix cal check step numbers and return tip, labware offset d…
Browse files Browse the repository at this point in the history
…ata help copy (#12423)

Fix logic that calculates the step number within the newly redesigned calibration health check flow
based on how many pipettes are being checked. Modernize contents of return tip step in cal check.
fix help copy in learn more about labware position check offsets.

Closes RQA-611, Closes RQA-609, Closes RAUT-393, Closes RQA-613
  • Loading branch information
b-cooper authored Apr 4, 2023
1 parent 4fca778 commit d1db655
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 117 deletions.
3 changes: 2 additions & 1 deletion app/src/assets/localization/en/device_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,6 @@
"clear_all_stored_data": "Clear all stored data",
"returns_your_device_to_new_state": "This returns your device to a new state.",
"not_connected": "Not connected",
"connected_via": "Connected via {{networkInterface}}"
"connected_via": "Connected via {{networkInterface}}",
"attach_a_pipette_before_calibrating": "Attach a pipette in order to perform calibration"
}
4 changes: 2 additions & 2 deletions app/src/assets/localization/en/labware_position_check.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
"slot": "Slot {{slotName}}",
"robot_has_offsets_from_previous_runs": "This robot has offsets for labware used in this protocol. If you apply these offsets, you can still adjust them with Labware Position Check.",
"no_offset_data_on_robot": "This robot has no useable labware offset data for this run.",
"what_labware_offset": "What is labware offset?",
"robot_has_no_offsets_from_previous_runs": "<block>Labware offset data references previous protocol run labware locations to save you time. Labware that has been used in the same slot as a protocol you are running will not need additional calibration. If all the labware in a new protocol have been checked in previous runs, you do not have to run Labware Position Check.</block> <block>You can add new offsets with Labware Position Check in later steps if you desire.</block>",
"what_is_labware_offset_data": "What is labware offset data?",
"robot_has_no_offsets_from_previous_runs": "<block>Labware offset data references previous protocol run labware locations to save you time. If all the labware in this protocol have been checked in previous runs, that data will be applied to this run.</block> <block>You can add new offsets with Labware Position Check in later steps.</block>",
"see_how_offsets_work": "See how labware offsets work",
"stored_offset_data": "Stored Labware Offset data",
"applied_offset_data": "Applied Labware Offset data",
Expand Down
6 changes: 5 additions & 1 deletion app/src/assets/localization/en/robot_calibration.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"check_tip_on_block": "Check tip on block",
"check_tip_on_trash": "Check tip on trash bin",
"check_xy_axes": "Check x- and y-axis in slot {{slotName}}",
"check_z_axis_on_slot": "Check z-axis on slot 5",
"check_z_axis_on_block": "Check z-axis on block",
"check_z_axis_on_trash": "Check z-axis on trash bin",
"clear_other_slots": "Clear all other deck slots",
Expand Down Expand Up @@ -124,5 +125,8 @@
"opentrons": "opentrons",
"custom": "custom",
"confirm_tip_rack": "Confirm tip rack",
"recalibrate_pipette": "Recalibrate pipette"
"recalibrate_pipette": "Recalibrate pipette",
"return_tip_and_continue": "Return tip and continue to next pipette",
"return_tip_and_exit": "Return tip and see calibration health check results",
"return_tip": "Return tip"
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,15 @@ describe('ApplyHistoricOffsets', () => {
getByText('No offset data available')
getByText('Learn more').click()

getByRole('heading', { name: 'No labware offset data available' })
getByText('This robot has no useable labware offset data for this run.')
getByText('What is labware offset?')
getByRole('heading', { name: 'What is labware offset data?' })

getByText(
'Labware offset data references previous protocol run labware locations to save you time. Labware that has been used in the same slot as a protocol you are running will not need additional calibration. If all the labware in a new protocol have been checked in previous runs, you do not have to run Labware Position Check.'
'Labware offset data references previous protocol run labware locations to save you time. If all the labware in this protocol have been checked in previous runs, that data will be applied to this run.'
)
getByText(
'You can add new offsets with Labware Position Check in later steps if you desire.'
'You can add new offsets with Labware Position Check in later steps.'
)

expect(
getByRole('link', { name: 'See how labware offsets work' })
).toHaveAttribute(
Expand Down
35 changes: 13 additions & 22 deletions app/src/organisms/ApplyHistoricOffsets/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type {
LoadedModule,
RunTimeCommand,
} from '@opentrons/shared-data'
import { ExternalLink } from '../../atoms/Link/ExternalLink'

const HOW_OFFSETS_WORK_SUPPORT_URL =
'https://support.opentrons.com/s/article/How-Labware-Offsets-work-on-the-OT-2'
Expand Down Expand Up @@ -110,7 +111,7 @@ export function ApplyHistoricOffsets(
<ModalHeader
title={t(
noOffsetData
? 'no_offset_data_available'
? 'what_is_labware_offset_data'
: 'stored_offset_data'
)}
onClose={() => setShowOffsetDataModal(false)}
Expand All @@ -126,36 +127,26 @@ export function ApplyHistoricOffsets(
}
>
{noOffsetData ? (
<>
<StyledText as="p" marginBottom={SPACING.spacing3}>
{t('no_offset_data_on_robot')}
</StyledText>
<StyledText css={TYPOGRAPHY.pSemiBold}>
{t('what_labware_offset')}
</StyledText>
<Trans
t={t}
i18nKey={'robot_has_no_offsets_from_previous_runs'}
components={{
block: (
<StyledText as="p" marginBottom={SPACING.spacing3} />
),
}}
/>
</>
<Trans
t={t}
i18nKey={'robot_has_no_offsets_from_previous_runs'}
components={{
block: (
<StyledText as="p" marginBottom={SPACING.spacing3} />
),
}}
/>
) : (
<StyledText as="p">
{t('robot_has_offsets_from_previous_runs')}
</StyledText>
)}
<Link
external
css={TYPOGRAPHY.linkPSemiBold}
<ExternalLink
marginTop={noOffsetData ? '0px' : SPACING.spacing3}
href={HOW_OFFSETS_WORK_SUPPORT_URL}
>
{t('see_how_offsets_work')}
</Link>
</ExternalLink>
{!noOffsetData ? (
isLabwareOffsetCodeSnippetsOn ? (
<LabwareOffsetTabs
Expand Down
13 changes: 4 additions & 9 deletions app/src/organisms/CalibrationPanels/SaveZPoint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const assetMap = {

export function SaveZPoint(props: CalibrationPanelProps): JSX.Element {
const { t } = useTranslation('robot_calibration')
const { isMulti, mount, sendCommands, sessionType, calBlock } = props
const { isMulti, mount, sendCommands, sessionType } = props
const demoAsset = React.useMemo(
() => mount && assetMap[mount][isMulti ? 'multi' : 'single'],
[mount, isMulti]
Expand Down Expand Up @@ -79,14 +79,9 @@ export function SaveZPoint(props: CalibrationPanelProps): JSX.Element {
)

let title = t('calibrate_z_axis_on_slot')
let bodyTranlsationKey = 'jog_pipette_to_touch_slot'
const bodyTranslationKey = 'jog_pipette_to_touch_slot'
if (isHealthCheck) {
title =
calBlock != null ? t('check_z_axis_on_block') : t('check_z_axis_on_trash')
bodyTranlsationKey =
calBlock != null
? 'jog_pipette_to_touch_block'
: 'jog_pipette_to_touch_trash'
title = t('check_z_axis_on_slot')
}

return (
Expand All @@ -108,7 +103,7 @@ export function SaveZPoint(props: CalibrationPanelProps): JSX.Element {
</StyledText>
<Trans
t={t}
i18nKey={bodyTranlsationKey}
i18nKey={bodyTranslationKey}
components={{
block: <StyledText as="p" marginBottom={SPACING.spacing3} />,
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,19 +168,19 @@ describe('SaveZPoint', () => {
sessionType: Sessions.SESSION_TYPE_CALIBRATION_HEALTH_CHECK,
calBlock: mockTipLengthCalBlock,
})[0]
getByRole('heading', { name: 'Check z-axis on block' })
getByRole('heading', { name: 'Check z-axis on slot 5' })
getByText(
'Jog the pipette until the tip is barely touching (less than 0.1 mm) the block in slot 6.'
'Jog the pipette until the tip is barely touching (less than 0.1 mm) the deck in slot 5.'
)
})

it('health check session type shows correct text without block', () => {
const { getByText, getByRole } = render({
sessionType: Sessions.SESSION_TYPE_CALIBRATION_HEALTH_CHECK,
})[0]
getByRole('heading', { name: 'Check z-axis on trash bin' })
getByRole('heading', { name: 'Check z-axis on slot 5' })
getByText(
'Jog the pipette until the tip is barely touching (less than 0.1 mm) the flat surface of the trash bin.'
'Jog the pipette until the tip is barely touching (less than 0.1 mm) the deck in slot 5.'
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import {
expectedIncompleteRightMountTaskList,
expectedIncompleteLeftMountTaskList,
} from '../../Devices/hooks/__fixtures__/taskListFixtures'
import { useCalibrationTaskList, useRunHasStarted } from '../../Devices/hooks'
import {
useCalibrationTaskList,
useRunHasStarted,
useAttachedPipettes,
} from '../../Devices/hooks'
import { mockLeftProtoPipette } from '../../../redux/pipettes/__fixtures__'

jest.mock('../../Devices/hooks')
jest.mock('../../ProtocolUpload/hooks')
Expand All @@ -26,6 +31,9 @@ const mockUseCalibrationTaskList = useCalibrationTaskList as jest.MockedFunction
const mockUseRunHasStarted = useRunHasStarted as jest.MockedFunction<
typeof useRunHasStarted
>
const mockUseAttachedPipettes = useAttachedPipettes as jest.MockedFunction<
typeof useAttachedPipettes
>

const render = (robotName: string = 'otie') => {
return renderWithProviders(
Expand All @@ -47,6 +55,10 @@ describe('CalibrationTaskList', () => {
beforeEach(() => {
mockUseCalibrationTaskList.mockReturnValue(expectedTaskList)
mockUseRunHasStarted.mockReturnValue(false)
mockUseAttachedPipettes.mockReturnValue({
left: mockLeftProtoPipette,
right: null,
})
})

afterEach(() => {
Expand Down
26 changes: 20 additions & 6 deletions app/src/organisms/CalibrationTaskList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import { StyledText } from '../../atoms/text'
import { Modal } from '../../molecules/Modal'
import { TaskList } from '../TaskList'

import { useCalibrationTaskList, useRunHasStarted } from '../Devices/hooks'
import {
useAttachedPipettes,
useCalibrationTaskList,
useRunHasStarted,
} from '../Devices/hooks'
import { useCurrentRunId } from '../ProtocolUpload/hooks'

import type { DashboardCalOffsetInvoker } from '../../pages/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset'
Expand Down Expand Up @@ -55,7 +59,21 @@ export function CalibrationTaskList({
deckCalLauncher
)
const runId = useCurrentRunId()

let generalTaskDisabledReason = null

const attachedPipettes = useAttachedPipettes()
if (attachedPipettes.left == null && attachedPipettes.right == null) {
generalTaskDisabledReason = t(
'device_settings:attach_a_pipette_before_calibrating'
)
}

const runHasStarted = useRunHasStarted(runId)
if (runHasStarted)
generalTaskDisabledReason = t(
'device_settings:some_robot_controls_are_not_available'
)

React.useEffect(() => {
if (
Expand Down Expand Up @@ -148,11 +166,7 @@ export function CalibrationTaskList({
taskList={taskList}
taskListStatus={taskListStatus}
generalTaskClickHandler={() => setHasLaunchedWizard(true)}
generalTaskDisabledReason={
runHasStarted
? t('device_settings:some_robot_controls_are_not_available')
: null
}
generalTaskDisabledReason={generalTaskDisabledReason}
/>
</>
)}
Expand Down
31 changes: 0 additions & 31 deletions app/src/organisms/CheckCalibration/ConfirmExitModal.tsx

This file was deleted.

50 changes: 26 additions & 24 deletions app/src/organisms/CheckCalibration/ReturnTip.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import * as React from 'react'
import {
Flex,
PrimaryBtn,
ALIGN_CENTER,
DIRECTION_COLUMN,
JUSTIFY_CENTER,
SPACING_3,
JUSTIFY_SPACE_BETWEEN,
SPACING,
ALIGN_STRETCH,
} from '@opentrons/components'
import uniq from 'lodash/uniq'

import * as Sessions from '../../redux/sessions'
import { StyledText } from '../../atoms/text'
import type { CalibrationPanelProps } from '../../organisms/CalibrationPanels/types'
import type { SessionCommandString } from '../../redux/sessions/types'

const CONFIRM_RETURN_BODY = 'Return tip and '
const CONTINUE_TO_NEXT = 'continue to next pipette'
const EXIT_PROGRAM = 'see calibration health check results'
const CONTINUE = 'continue to the next tiprack'
const EXIT = 'continue to the result summary'
import { useTranslation } from 'react-i18next'
import { PrimaryButton } from '../../atoms/buttons'
import { NeedHelpLink } from '../CalibrationPanels'

export function ReturnTip(props: CalibrationPanelProps): JSX.Element {
const { t } = useTranslation('robot_calibration')
const { sendCommands, checkBothPipettes, activePipette, instruments } = props
const onFinalPipette =
!checkBothPipettes ||
Expand Down Expand Up @@ -55,23 +52,28 @@ export function ReturnTip(props: CalibrationPanelProps): JSX.Element {
}
return (
<Flex
width="100%"
flexDirection={DIRECTION_COLUMN}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_CENTER}
justifyContent={JUSTIFY_SPACE_BETWEEN}
padding={SPACING.spacing6}
minHeight="32rem"
>
<StyledText as="h1" marginBottom={SPACING_3}>
{`${CONFIRM_RETURN_BODY}
${onFinalPipette ? EXIT_PROGRAM : CONTINUE_TO_NEXT}`}
</StyledText>
<PrimaryBtn
title="confirmReturnTip"
marginTop={SPACING_3}
width="80%"
onClick={confirmReturnTip}
<Flex alignSelf={ALIGN_STRETCH}>
<StyledText as="h1">
{onFinalPipette
? t('return_tip_and_exit')
: t('return_tip_and_continue')}
</StyledText>
</Flex>
<Flex
width="100%"
justifyContent={JUSTIFY_SPACE_BETWEEN}
marginTop={SPACING.spacing4}
>
{onFinalPipette ? EXIT : CONTINUE}
</PrimaryBtn>
<NeedHelpLink />
<PrimaryButton aria-label="return tip" onClick={confirmReturnTip}>
{t('return_tip')}
</PrimaryButton>
</Flex>
</Flex>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('CheckCalibration', () => {
heading: 'Did pipette pick up tip successfully?',
currentStep: 'inspectingTip',
},
{ heading: 'Check z-axis on trash bin', currentStep: 'comparingHeight' },
{ heading: 'Check z-axis on slot 5', currentStep: 'comparingHeight' },
{
heading: 'Check x- and y-axis in slot 1',
currentStep: 'comparingPointOne',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('ReturnTip', () => {

const getContinueButton = (
wrapper: ReactWrapper<React.ComponentProps<typeof ReturnTip>>
) => wrapper.find('button[title="confirmReturnTip"]')
) => wrapper.find('button[aria-label="return tip"]')

beforeEach(() => {
mockSendCommands = jest.fn()
Expand Down
Loading

0 comments on commit d1db655

Please sign in to comment.