Skip to content

Commit

Permalink
refactor(app): Update dropTipInPlace command text (#16610)
Browse files Browse the repository at this point in the history
Closes EXEC-182

This commit updates tip drop command text when trash is dropped into a waste container, increasing specificity. Unfortunately, the command metadata itself does not give any location when performing a drop tip, so the app must derive the location from looking at the most recent addressableArea command. Fortunately, this should never be a compute-heavy scan unless the protocol does something like "move to trash" followed by a ton of "dispense over trash" before dropping tips, which seems quite unlikely in practice. Regardless, this instance serves as an example of places in which we should reduce compute done on the app in the future.
  • Loading branch information
mjhuff authored Oct 28, 2024
1 parent cebe51a commit 288b8a4
Show file tree
Hide file tree
Showing 36 changed files with 317 additions and 95 deletions.
9 changes: 5 additions & 4 deletions app/src/assets/localization/en/protocol_command_text.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"absorbance_reader_open_lid": "Opening Absorbance Reader lid",
"absorbance_reader_close_lid": "Closing Absorbance Reader lid",
"absorbance_reader_initialize": "Initializing Absorbance Reader to perform {{mode}} measurement at {{wavelengths}}",
"absorbance_reader_open_lid": "Opening Absorbance Reader lid",
"absorbance_reader_read": "Reading plate in Absorbance Reader",
"adapter_in_mod_in_slot": "{{adapter}} on {{module}} in {{slot}}",
"adapter_in_slot": "{{adapter}} in {{slot}}",
Expand All @@ -27,6 +27,7 @@
"dispense_push_out": "Dispensing {{volume}} µL into well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec and pushing out {{push_out_volume}} µL",
"drop_tip": "Dropping tip in {{well_name}} of {{labware}}",
"drop_tip_in_place": "Dropping tip in place",
"dropping_tip_in_trash": "Dropping tip in {{trash}}",
"engaging_magnetic_module": "Engaging Magnetic Module",
"fixed_trash": "Fixed Trash",
"home_gantry": "Homing all gantry, pipette, and plunger axes",
Expand Down Expand Up @@ -73,16 +74,16 @@
"setting_thermocycler_lid_temp": "Setting Thermocycler lid temperature to {{temp}}",
"single": "single",
"slot": "Slot {{slot_name}}",
"turning_rail_lights_off": "Turning rail lights off",
"turning_rail_lights_on": "Turning rail lights on",
"target_temperature": "target temperature",
"tc_awaiting_for_duration": "Waiting for Thermocycler profile to complete",
"tc_run_profile_steps": "Temperature: {{celsius}}°C, hold time: {{duration}}",
"tc_starting_extended_profile_cycle": "{{repetitions}} repetitions of the following steps:",
"tc_starting_extended_profile": "Running thermocycler profile with {{elementCount}} total steps and cycles:",
"tc_starting_extended_profile_cycle": "{{repetitions}} repetitions of the following steps:",
"tc_starting_profile": "Running thermocycler profile with {{stepCount}} steps:",
"touch_tip": "Touching tip",
"trash_bin_in_slot": "Trash Bin in {{slot_name}}",
"turning_rail_lights_off": "Turning rail lights off",
"turning_rail_lights_on": "Turning rail lights on",
"unlatching_hs_latch": "Unlatching labware on Heater-Shaker",
"wait_for_duration": "Pausing for {{seconds}} seconds. {{message}}",
"wait_for_resume": "Pausing protocol",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import type {
RobotType,
LabwareDefinition2,
} from '@opentrons/shared-data'
import type { GetDirectTranslationCommandText } from './utils/getDirectTranslationCommandText'
import type {
TCProfileStepText,
TCProfileCycleText,
} from './utils/getTCRunExtendedProfileCommandText'
GetDirectTranslationCommandText,
} from './utils'
import type { CommandTextData } from '/app/local-resources/commands/types'

export interface UseCommandTextStringParams {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { screen } from '@testing-library/react'
import { vi, describe, it, beforeEach } from 'vitest'
import { useTranslation } from 'react-i18next'

import { renderWithProviders } from '/app/__testing-utils__'
import { i18n } from '/app/i18n'
import {
getLabwareDefinitionsFromCommands,
getLabwareName,
getLoadedLabware,
getLabwareDisplayLocation,
} from '/app/local-resources/labware'
import { getPipettingCommandText } from '../getPipettingCommandText'
import { getLabwareDefURI } from '@opentrons/shared-data'
import { getFinalLabwareLocation } from '../../getFinalLabwareLocation'
import { getWellRange } from '../../getWellRange'
import { getFinalMoveToAddressableAreaCmd } from '../../getFinalAddressableAreaCmd'
import { getAddressableAreaDisplayName } from '../../getAddressableAreaDisplayName'

vi.mock('@opentrons/shared-data')
vi.mock('../../getFinalLabwareLocation')
vi.mock('../../getWellRange')
vi.mock('/app/local-resources/labware')
vi.mock('../../getFinalAddressableAreaCmd')
vi.mock('../../getAddressableAreaDisplayName')

const baseCommandData = {
allRunDefs: {},
robotType: 'OT-2',
commandTextData: {
commands: [],
labware: [],
modules: [],
pipettes: [{ id: 'pipette-1', pipetteName: 'p300_single' }],
},
} as any

function TestWrapper({ command }: { command: any }): JSX.Element {
const { t } = useTranslation('protocol_command_text')
const text = getPipettingCommandText({
command,
...baseCommandData,
t,
})

return <div>{text}</div>
}

const render = (command: any) => {
return renderWithProviders(<TestWrapper command={command} />, {
i18nInstance: i18n,
})
}

describe('getPipettingCommandText', () => {
beforeEach(() => {
vi.mocked(getLabwareDefURI).mockImplementation((def: any) => def.uri)
vi.mocked(getFinalLabwareLocation).mockReturnValue('slot-1' as any)
vi.mocked(getWellRange).mockReturnValue('A1')
vi.mocked(getLabwareDefinitionsFromCommands).mockReturnValue([
{ uri: 'tiprack-uri', parameters: { isTiprack: true } },
{ uri: 'plate-uri', parameters: { isTiprack: false } },
] as any)
vi.mocked(getLabwareName).mockReturnValue('Test Labware')
vi.mocked(getLoadedLabware).mockImplementation(
(labware, id) =>
({
definitionUri: id === 'tiprack-id' ? 'tiprack-uri' : 'plate-uri',
} as any)
)
vi.mocked(getLabwareDisplayLocation).mockReturnValue('Slot 1')
vi.mocked(getFinalMoveToAddressableAreaCmd).mockReturnValue({
id: 'cmd-1',
commandType: 'moveToAddressableArea',
} as any)
vi.mocked(getAddressableAreaDisplayName).mockReturnValue('Fixed Trash')
})

it('should render aspirate command text correctly', () => {
const command = {
id: 'cmd-1',
commandType: 'aspirate',
params: {
labwareId: 'labware-1',
wellName: 'A1',
volume: 100,
flowRate: 150,
},
}

render(command)
screen.getByText(
/Aspirating 100 µL from well A1 of Test Labware in Slot 1 at 150 µL\/sec/
)
})

it('should render dispense command text correctly', () => {
const command = {
id: 'cmd-1',
commandType: 'dispense',
params: {
labwareId: 'labware-1',
wellName: 'A1',
volume: 100,
flowRate: 150,
},
}

render(command)
screen.getByText(
/Dispensing 100 µL into well A1 of Test Labware in Slot 1 at 150 µL\/sec/
)
})

it('should render dispense with push out command text correctly', () => {
const command = {
id: 'cmd-1',
commandType: 'dispense',
params: {
labwareId: 'labware-1',
wellName: 'A1',
volume: 100,
flowRate: 150,
pushOut: 10,
},
}

render(command)
screen.getByText(
/Dispensing 100 µL into well A1 of Test Labware in Slot 1 at 150 µL\/sec and pushing out 10 µL/
)
})

it('should render pickup tip command text correctly', () => {
const command = {
id: 'cmd-1',
commandType: 'pickUpTip',
params: {
labwareId: 'tiprack-id',
wellName: 'A1',
pipetteId: 'pipette-1',
},
}

render(command)
screen.getByText(/Picking up tip\(s\) from A1 of Test Labware in Slot 1/)
})

it('should render drop tip in tiprack command text correctly', () => {
const command = {
id: 'cmd-1',
commandType: 'dropTip',
params: {
labwareId: 'tiprack-id',
wellName: 'A1',
},
}

render(command)
screen.getByText(/Returning tip to A1 of Test Labware in Slot 1/)
})

it('should render drop tip in place command text correctly if there is an addressable area name', () => {
const command = {
id: 'cmd-1',
commandType: 'dropTipInPlace',
params: {},
}

render(command)
screen.getByText('Dropping tip in Fixed Trash')
})

it('should render drop tip in place command text correctly if there is not an addressable area name', () => {
const command = {
id: 'cmd-1',
commandType: 'dropTipInPlace',
params: {},
}

vi.mocked(getFinalMoveToAddressableAreaCmd).mockReturnValue(null)

render(command)
screen.getByText('Dropping tip in place')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
AbsorbanceReaderReadRunTimeCommand,
RunTimeCommand,
} from '@opentrons/shared-data'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export type AbsorbanceCreateCommand =
| AbsorbanceReaderOpenLidRunTimeCommand
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { CommentRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getCommentCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getPipetteSpecsV2 } from '@opentrons/shared-data'

import type { ConfigureForVolumeRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getConfigureForVolumeCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getPipetteSpecsV2 } from '@opentrons/shared-data'

import type { ConfigureNozzleLayoutRunTimeCommand } from '@opentrons/shared-data'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getConfigureNozzleLayoutCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { CustomRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getCustomCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { DeprecatedDelayRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getDelayCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { RunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

const SIMPLE_TRANSLATION_KEY_BY_COMMAND_TYPE: {
[commandType in RunTimeCommand['commandType']]?: string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { HeaterShakerSetAndWaitForShakeSpeedRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getHSShakeSpeedCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import {
getLabwareName,
getLabwareDisplayLocation,
} from '/app/local-resources/labware'
import { getFinalLabwareLocation } from './getFinalLabwareLocation'
import { getFinalLabwareLocation } from '../getFinalLabwareLocation'

import type {
LiquidProbeRunTimeCommand,
RunTimeCommand,
TryLiquidProbeRunTimeCommand,
} from '@opentrons/shared-data'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

type LiquidProbeRunTimeCommands =
| LiquidProbeRunTimeCommand
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
getPipetteSpecsV2,
} from '@opentrons/shared-data'

import { getPipetteNameOnMount } from './getPipetteNameOnMount'
import { getLiquidDisplayName } from './getLiquidDisplayName'
import { getPipetteNameOnMount } from '../getPipetteNameOnMount'
import { getLiquidDisplayName } from '../getLiquidDisplayName'

import { getLabwareName } from '/app/local-resources/labware'
import {
Expand All @@ -15,7 +15,7 @@ import {
} from '/app/local-resources/modules'

import type { LoadLabwareRunTimeCommand } from '@opentrons/shared-data'
import type { GetCommandText } from '..'
import type { GetCommandText } from '../..'

export const getLoadCommandText = ({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { GRIPPER_WASTE_CHUTE_ADDRESSABLE_AREA } from '@opentrons/shared-data'

import { getFinalLabwareLocation } from './getFinalLabwareLocation'
import { getFinalLabwareLocation } from '../getFinalLabwareLocation'
import {
getLabwareName,
getLabwareDisplayLocation,
} from '/app/local-resources/labware'

import type { MoveLabwareRunTimeCommand } from '@opentrons/shared-data'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getMoveLabwareCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { MoveRelativeRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getMoveRelativeCommandText({
command,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getAddressableAreaDisplayName } from './getAddressableAreaDisplayName'
import { getAddressableAreaDisplayName } from '../getAddressableAreaDisplayName'

import type { MoveToAddressableAreaRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getMoveToAddressableAreaCommandText({
command,
Expand All @@ -10,7 +10,7 @@ export function getMoveToAddressableAreaCommandText({
}: HandlesCommands<MoveToAddressableAreaRunTimeCommand>): string {
const addressableAreaDisplayName =
commandTextData != null
? getAddressableAreaDisplayName(commandTextData, command.id, t)
? getAddressableAreaDisplayName(commandTextData.commands, command.id, t)
: null

return t('move_to_addressable_area', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getAddressableAreaDisplayName } from './getAddressableAreaDisplayName'
import { getAddressableAreaDisplayName } from '../getAddressableAreaDisplayName'

import type { MoveToAddressableAreaForDropTipRunTimeCommand } from '@opentrons/shared-data/command'
import type { HandlesCommands } from './types'
import type { HandlesCommands } from '../types'

export function getMoveToAddressableAreaForDropTipCommandText({
command,
Expand All @@ -10,7 +10,7 @@ export function getMoveToAddressableAreaForDropTipCommandText({
}: HandlesCommands<MoveToAddressableAreaForDropTipRunTimeCommand>): string {
const addressableAreaDisplayName =
commandTextData != null
? getAddressableAreaDisplayName(commandTextData, command.id, t)
? getAddressableAreaDisplayName(commandTextData.commands, command.id, t)
: null

return t('move_to_addressable_area_drop_tip', {
Expand Down
Loading

0 comments on commit 288b8a4

Please sign in to comment.