Skip to content

Commit 75aea30

Browse files
committed
refactor(app): refactor CommandText
Decouple the logic that generates command text from the component that renders it.
1 parent 67097d7 commit 75aea30

28 files changed

+919
-566
lines changed

app/src/molecules/Command/CommandText.tsx

Lines changed: 94 additions & 397 deletions
Large diffs are not rendered by default.

app/src/molecules/Command/MoveLabwareCommandText.tsx

Lines changed: 0 additions & 70 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export { useCommandTextString } from './useCommandTextString'
2+
3+
export type {
4+
UseCommandTextStringParams,
5+
GetCommandText,
6+
GetCommandTextResult,
7+
} from './useCommandTextString'
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import { useTranslation } from 'react-i18next'
2+
import * as utils from './utils'
3+
4+
import type { TFunction } from 'i18next'
5+
import type { RunTimeCommand } from '@opentrons/shared-data/command'
6+
import type { RobotType } from '@opentrons/shared-data/lib/js'
7+
import type { CommandTextData } from '../../types'
8+
9+
export interface UseCommandTextStringParams {
10+
command: RunTimeCommand | null
11+
commandTextData: CommandTextData | null
12+
robotType: RobotType
13+
}
14+
15+
export type GetCommandText = UseCommandTextStringParams & { t: TFunction }
16+
export interface GetCommandTextResult {
17+
/* The actual command text. Ex "Homing all gantry, pipette, and plunger axes" */
18+
commandText: string
19+
/* The TC run profile steps. */
20+
stepTexts?: string[]
21+
}
22+
23+
// TODO(jh, 07-18-24): Move the testing that covers this from CommandText to a new file, and verify that all commands are
24+
// properly tested.
25+
26+
// Get the full user-facing command text string from a given command.
27+
export function useCommandTextString(
28+
params: UseCommandTextStringParams
29+
): GetCommandTextResult {
30+
const { command } = params
31+
const { t } = useTranslation('protocol_command_text')
32+
33+
const fullParams = { ...params, t }
34+
35+
switch (command?.commandType) {
36+
case 'touchTip':
37+
case 'home':
38+
case 'savePosition':
39+
case 'magneticModule/engage':
40+
case 'magneticModule/disengage':
41+
case 'temperatureModule/deactivate':
42+
case 'thermocycler/waitForBlockTemperature':
43+
case 'thermocycler/waitForLidTemperature':
44+
case 'thermocycler/openLid':
45+
case 'thermocycler/closeLid':
46+
case 'thermocycler/deactivateBlock':
47+
case 'thermocycler/deactivateLid':
48+
case 'thermocycler/awaitProfileComplete':
49+
case 'heaterShaker/deactivateHeater':
50+
case 'heaterShaker/openLabwareLatch':
51+
case 'heaterShaker/closeLabwareLatch':
52+
case 'heaterShaker/deactivateShaker':
53+
case 'heaterShaker/waitForTemperature':
54+
return {
55+
commandText: utils.getDirectTranslationCommandText(fullParams),
56+
}
57+
58+
case 'aspirate':
59+
case 'aspirateInPlace':
60+
case 'dispense':
61+
case 'dispenseInPlace':
62+
case 'blowout':
63+
case 'blowOutInPlace':
64+
case 'dropTip':
65+
case 'dropTipInPlace':
66+
case 'pickUpTip':
67+
return {
68+
commandText: utils.getPipettingCommandText(fullParams),
69+
}
70+
71+
case 'loadLabware':
72+
case 'loadPipette':
73+
case 'loadModule':
74+
case 'loadLiquid':
75+
return {
76+
commandText: utils.getLoadCommandText(fullParams),
77+
}
78+
79+
case 'temperatureModule/setTargetTemperature':
80+
case 'temperatureModule/waitForTemperature':
81+
case 'thermocycler/setTargetBlockTemperature':
82+
case 'thermocycler/setTargetLidTemperature':
83+
case 'heaterShaker/setTargetTemperature':
84+
return {
85+
commandText: utils.getTemperatureCommandText({
86+
...fullParams,
87+
command,
88+
}),
89+
}
90+
91+
case 'thermocycler/runProfile':
92+
return utils.getTCRunProfileCommandText({ ...fullParams, command })
93+
94+
case 'heaterShaker/setAndWaitForShakeSpeed':
95+
return {
96+
commandText: utils.getHSShakeSpeedCommandText({
97+
...fullParams,
98+
command,
99+
}),
100+
}
101+
102+
case 'moveToSlot':
103+
return {
104+
commandText: utils.getMoveToSlotCommandText({ ...fullParams, command }),
105+
}
106+
107+
case 'moveRelative':
108+
return {
109+
commandText: utils.getMoveRelativeCommandText({
110+
...fullParams,
111+
command,
112+
}),
113+
}
114+
115+
case 'moveToCoordinates':
116+
return {
117+
commandText: utils.getMoveToCoordinatesCommandText({
118+
...fullParams,
119+
command,
120+
}),
121+
}
122+
123+
case 'moveToWell':
124+
return {
125+
commandText: utils.getMoveToWellCommandText({ ...fullParams, command }),
126+
}
127+
128+
case 'moveLabware':
129+
return {
130+
commandText: utils.getMoveLabwareCommandText({
131+
...fullParams,
132+
command,
133+
}),
134+
}
135+
136+
case 'configureForVolume':
137+
return {
138+
commandText: utils.getConfigureForVolumeCommandText({
139+
...fullParams,
140+
command,
141+
}),
142+
}
143+
144+
case 'configureNozzleLayout':
145+
return {
146+
commandText: utils.getConfigureNozzleLayoutCommandText({
147+
...fullParams,
148+
command,
149+
}),
150+
}
151+
152+
case 'prepareToAspirate':
153+
return {
154+
commandText: utils.getPrepareToAspirateCommandText({
155+
...fullParams,
156+
command,
157+
}),
158+
}
159+
160+
case 'moveToAddressableArea':
161+
return {
162+
commandText: utils.getMoveToAddressableAreaCommandText({
163+
...fullParams,
164+
command,
165+
}),
166+
}
167+
168+
case 'moveToAddressableAreaForDropTip':
169+
return {
170+
commandText: utils.getMoveToAddressableAreaForDropTipCommandText({
171+
...fullParams,
172+
command,
173+
}),
174+
}
175+
176+
case 'waitForDuration':
177+
return {
178+
commandText: utils.getWaitForDurationCommandText({
179+
...fullParams,
180+
command,
181+
}),
182+
}
183+
184+
case 'pause': // legacy pause command
185+
case 'waitForResume':
186+
return {
187+
commandText: utils.getWaitForResumeCommandText({
188+
...fullParams,
189+
command,
190+
}),
191+
}
192+
193+
case 'delay':
194+
return {
195+
commandText: utils.getDelayCommandText({ ...fullParams, command }),
196+
}
197+
198+
case 'comment':
199+
return {
200+
commandText: utils.getCommentCommandText({ ...fullParams, command }),
201+
}
202+
203+
case 'custom':
204+
return {
205+
commandText: utils.getCustomCommandText({ ...fullParams, command }),
206+
}
207+
208+
case null:
209+
return { commandText: '' }
210+
211+
default:
212+
console.warn(
213+
'CommandText encountered a command with an unrecognized commandType: ',
214+
command
215+
)
216+
return {
217+
commandText: utils.getUnknownCommandText({ ...fullParams, command }),
218+
}
219+
}
220+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { CommentRunTimeCommand } from '@opentrons/shared-data/command'
2+
import type { GetCommandText } from '..'
3+
4+
type GetCommentCommandText = Omit<GetCommandText, 'command'> & {
5+
command: CommentRunTimeCommand
6+
}
7+
8+
export function getCommentCommandText({
9+
command,
10+
}: GetCommentCommandText): string {
11+
const { message } = command.params
12+
13+
return message
14+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getPipetteNameSpecs } from '@opentrons/shared-data'
2+
3+
import type { ConfigureForVolumeRunTimeCommand } from '@opentrons/shared-data/command'
4+
import type { GetCommandText } from '..'
5+
6+
type GetConfigureForVolumeCommandText = Omit<GetCommandText, 'command'> & {
7+
command: ConfigureForVolumeRunTimeCommand
8+
}
9+
10+
export function getConfigureForVolumeCommandText({
11+
command,
12+
commandTextData,
13+
t,
14+
}: GetConfigureForVolumeCommandText): string {
15+
const { volume, pipetteId } = command.params
16+
const pipetteName = commandTextData?.pipettes.find(
17+
pip => pip.id === pipetteId
18+
)?.pipetteName
19+
20+
return t('configure_for_volume', {
21+
volume,
22+
pipette:
23+
pipetteName != null ? getPipetteNameSpecs(pipetteName)?.displayName : '',
24+
})
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getPipetteNameSpecs } from '@opentrons/shared-data'
2+
3+
import type { ConfigureNozzleLayoutRunTimeCommand } from '@opentrons/shared-data/command'
4+
import type { GetCommandText } from '..'
5+
6+
type GetConfigureNozzleLayoutCommandText = Omit<GetCommandText, 'command'> & {
7+
command: ConfigureNozzleLayoutRunTimeCommand
8+
}
9+
10+
export function getConfigureNozzleLayoutCommandText({
11+
command,
12+
commandTextData,
13+
t,
14+
}: GetConfigureNozzleLayoutCommandText): string {
15+
const { configurationParams, pipetteId } = command.params
16+
const pipetteName = commandTextData?.pipettes.find(
17+
pip => pip.id === pipetteId
18+
)?.pipetteName
19+
20+
return t('configure_nozzle_layout', {
21+
amount: configurationParams.style === 'COLUMN' ? '8' : 'all',
22+
pipette:
23+
pipetteName != null ? getPipetteNameSpecs(pipetteName)?.displayName : '',
24+
})
25+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { CustomRunTimeCommand } from '@opentrons/shared-data/command'
2+
import type { GetCommandText } from '..'
3+
4+
type GetCustomCommandText = Omit<GetCommandText, 'command'> & {
5+
command: CustomRunTimeCommand
6+
}
7+
8+
export function getCustomCommandText({
9+
command,
10+
}: GetCustomCommandText): string {
11+
const { legacyCommandText } = command.params ?? {}
12+
const sanitizedCommandText =
13+
typeof legacyCommandText === 'object'
14+
? JSON.stringify(legacyCommandText)
15+
: String(legacyCommandText)
16+
17+
return legacyCommandText != null
18+
? sanitizedCommandText
19+
: `${command.commandType}: ${JSON.stringify(command.params)}`
20+
}

0 commit comments

Comments
 (0)