Skip to content

Commit 9e5f63a

Browse files
authored
feat(protocol-designer): add absorbance reader step summaries (#18932)
This PR adds and wires up the new AbsorbanceReaderSummary component in StepSummary. It also refactors a styled component for the summary container over to the new CSS modules paradigm. Closes AUTH-1431
1 parent 7d121d8 commit 9e5f63a

File tree

5 files changed

+166
-16
lines changed

5 files changed

+166
-16
lines changed

protocol-designer/src/assets/localization/en/protocol_steps.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
{
2+
"absorbance_reader": {
3+
"closed": "closed",
4+
"initialize_lid": "<text>Plate reader changing lid position to</text><tag/>",
5+
"initialize_multi": "Initializing plate reader wavelength to",
6+
"initialize_single": "<text>Initializing plate reader wavelength to</text><tag/>",
7+
"initialize_single_with_reference": "<text>Initializing plate reader wavelength to</text><tag/><text>with reference wavelength</text><tag2/>",
8+
"open": "open",
9+
"read": "<text>Plate reader reading</text><tag/><text>Saving file as</text><tag2/>",
10+
"reference": "<text>with reference wavelength</text><tag/>"
11+
},
212
"add_details": "Add step details",
313
"advanced_settings": "Advanced pipetting settings",
414
"air_gap_volume": "Air gap volume",
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { Fragment } from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
4+
import { StyledText, Tag } from '@opentrons/components'
5+
6+
import {
7+
ABSORBANCE_READER_INITIALIZE,
8+
ABSORBANCE_READER_LID,
9+
ABSORBANCE_READER_READ,
10+
} from '../../../constants'
11+
import { StyledTrans } from './StyledTrans'
12+
import styles from './summary.module.css'
13+
14+
import type { RobotState } from '@opentrons/step-generation'
15+
import type { FormData } from '../../../form-types'
16+
17+
interface AbsorbanceReaderSummaryProps {
18+
currentStep: FormData
19+
labwareNicknamesById: Record<string, string>
20+
labwareState: RobotState['labware']
21+
}
22+
23+
export function AbsorbanceReaderSummary(
24+
props: AbsorbanceReaderSummaryProps
25+
): JSX.Element | null {
26+
const { t } = useTranslation('protocol_steps')
27+
const { currentStep, labwareNicknamesById, labwareState } = props
28+
const {
29+
moduleId: absorbanceReaderModuleId,
30+
absorbanceReaderFormType,
31+
fileName,
32+
lidOpen,
33+
mode,
34+
referenceWavelength,
35+
referenceWavelengthActive,
36+
wavelengths,
37+
} = currentStep
38+
const labwareOnAbsorbanceReaderId = Object.values(
39+
labwareState
40+
).find(({ stack }) => stack.includes(absorbanceReaderModuleId as string))
41+
?.stack[0] // top element of stack including absorbance reader
42+
const labwareOnAbsorbanceReaderNickname =
43+
labwareOnAbsorbanceReaderId != null
44+
? labwareNicknamesById[labwareOnAbsorbanceReaderId]
45+
: null
46+
let stepSummaryContent: JSX.Element | null = null
47+
switch (absorbanceReaderFormType) {
48+
case ABSORBANCE_READER_READ: {
49+
stepSummaryContent = (
50+
<StyledTrans
51+
i18nKey="protocol_steps:absorbance_reader.read"
52+
{...(labwareOnAbsorbanceReaderNickname != null
53+
? {
54+
tagText: labwareOnAbsorbanceReaderNickname,
55+
}
56+
: {})}
57+
tagText2={fileName}
58+
/>
59+
)
60+
break
61+
}
62+
case ABSORBANCE_READER_INITIALIZE: {
63+
const wavelengthsComponents = (
64+
<div className={styles.absorbance_reader}>
65+
{wavelengths.map((wavelength: string, index: number) => (
66+
<Fragment key={`${wavelength}-${index}`}>
67+
<Tag
68+
text={`${wavelength} ${t('application:units.nanometer')}`}
69+
type="default"
70+
/>
71+
{index < wavelengths.length - 1 ? (
72+
<StyledText>,</StyledText>
73+
) : null}
74+
</Fragment>
75+
))}
76+
</div>
77+
)
78+
if (mode === 'single') {
79+
stepSummaryContent =
80+
referenceWavelengthActive === true && referenceWavelength != null ? (
81+
<StyledTrans
82+
i18nKey="protocol_steps:absorbance_reader.initialize_single_with_reference"
83+
tagText={`${wavelengths[0]}${t('application:units.nanometer')}`}
84+
tagText2={`${referenceWavelength}${t(
85+
'application:units.nanometer'
86+
)}`}
87+
/>
88+
) : (
89+
<StyledTrans
90+
i18nKey="protocol_steps:absorbance_reader.initialize_single"
91+
tagText={`${wavelengths[0]}${t('application:units.nanometer')}`}
92+
/>
93+
)
94+
break
95+
}
96+
// mode is multi
97+
stepSummaryContent = (
98+
<div className={styles.absorbance_reader}>
99+
<StyledText desktopStyle="bodyDefaultRegular">
100+
{t('protocol_steps:absorbance_reader.initialize_multi')}
101+
</StyledText>
102+
{wavelengthsComponents}
103+
</div>
104+
)
105+
break
106+
}
107+
case ABSORBANCE_READER_LID: {
108+
stepSummaryContent = (
109+
<StyledTrans
110+
i18nKey="protocol_steps:absorbance_reader.initialize_lid"
111+
tagText={t(
112+
`protocol_steps:absorbance_reader.${
113+
lidOpen === true ? 'open' : 'closed'
114+
}`
115+
)}
116+
/>
117+
)
118+
break
119+
}
120+
}
121+
return stepSummaryContent
122+
}

protocol-designer/src/components/organisms/StepSummary/StyledTrans.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ import {
1313
interface StyledTransProps {
1414
i18nKey: string
1515
tagText?: string
16+
tagText2?: string
1617
values?: object
1718
}
1819

1920
export function StyledTrans(props: StyledTransProps): JSX.Element {
20-
const { i18nKey, tagText, values } = props
21+
const { i18nKey, tagText, tagText2, values } = props
2122
const { t } = useTranslation(['protocol_steps', 'application'])
2223

2324
return (
@@ -39,6 +40,7 @@ export function StyledTrans(props: StyledTransProps): JSX.Element {
3940
/>
4041
),
4142
tag: <Tag type="default" text={tagText ?? ''} />,
43+
tag2: <Tag type="default" text={tagText2 ?? ''} />,
4244
}}
4345
values={values}
4446
/>

protocol-designer/src/components/organisms/StepSummary/index.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { useTranslation } from 'react-i18next'
22
import { useSelector } from 'react-redux'
3-
import styled from 'styled-components'
43

54
import {
65
DIRECTION_COLUMN,
76
Flex,
87
ListItem,
98
SPACING,
109
StyledText,
11-
WRAP,
1210
} from '@opentrons/components'
1311
import {
1412
getModuleDisplayName,
@@ -25,9 +23,11 @@ import {
2523
import { getRobotStateAtActiveItem } from '../../../top-selectors/labware-locations'
2624
import { getLabwareNicknamesById } from '../../../ui/labware/selectors'
2725
import { LINE_CLAMP_TEXT_STYLE } from '../../atoms'
26+
import { AbsorbanceReaderSummary } from './AbsorbanceReaderSummary'
2827
import { MixSummary } from './MixSummary'
2928
import { MoveLiquidSummary } from './MoveLiquidSummary'
3029
import { StyledTrans } from './StyledTrans'
30+
import styles from './summary.module.css'
3131

3232
import type { FormData } from '../../../form-types'
3333

@@ -55,7 +55,7 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
5555
return null
5656
}
5757
const { stepType } = currentStep
58-
const { liquidState } = robotState
58+
const { labware: labwareState, liquidState } = robotState
5959
let stepSummaryContent: JSX.Element | null = null
6060
switch (stepType) {
6161
case 'mix': {
@@ -112,7 +112,7 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
112112
} = currentStep
113113
stepSummaryContent =
114114
thermocyclerFormType === 'thermocyclerState' ? (
115-
<StepSummaryContainer>
115+
<div className={styles.container}>
116116
{blockIsActive ? (
117117
<StyledTrans
118118
i18nKey="protocol_steps:thermocycler_module.thermocycler_state.block"
@@ -133,9 +133,9 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
133133
}`
134134
)}
135135
/>
136-
</StepSummaryContainer>
136+
</div>
137137
) : (
138-
<StepSummaryContainer>
138+
<div className={styles.container}>
139139
<StyledTrans
140140
i18nKey="protocol_steps:thermocycler_module.thermocycler_profile.volume"
141141
tagText={`${profileVolume} ${t('application:units.microliter')}`}
@@ -160,7 +160,7 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
160160
}`
161161
)}
162162
/>
163-
</StepSummaryContainer>
163+
</div>
164164
)
165165
break
166166
}
@@ -289,7 +289,7 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
289289
const moduleDisplayName =
290290
moduleModel != null ? getModuleDisplayName(moduleModel) : unknownModule
291291
stepSummaryContent = (
292-
<StepSummaryContainer>
292+
<div className={styles.container}>
293293
<StyledTrans
294294
i18nKey="protocol_steps:heater_shaker.active.temperature"
295295
values={{ module: moduleDisplayName }}
@@ -321,7 +321,17 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
321321
: 'protocol_steps:heater_shaker.latch.closed'
322322
)}
323323
/>
324-
</StepSummaryContainer>
324+
</div>
325+
)
326+
break
327+
}
328+
case 'absorbanceReader': {
329+
stepSummaryContent = (
330+
<AbsorbanceReaderSummary
331+
currentStep={currentStep}
332+
labwareNicknamesById={labwareNicknamesById}
333+
labwareState={labwareState}
334+
/>
325335
)
326336
break
327337
}
@@ -357,9 +367,3 @@ export function StepSummary(props: StepSummaryProps): JSX.Element | null {
357367
</Flex>
358368
) : null
359369
}
360-
361-
const StepSummaryContainer = styled(Flex)`
362-
flex-wrap: ${WRAP};
363-
gap: ${SPACING.spacing20};
364-
row-gap: ${SPACING.spacing4};
365-
`
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.container {
2+
display: flex;
3+
flex-wrap: wrap;
4+
gap: var(--spacing-20);
5+
row-gap: var(--spacing-4);
6+
}
7+
8+
.absorbance_reader {
9+
display: flex;
10+
align-items: center;
11+
grid-gap: var(--spacing-4);
12+
}

0 commit comments

Comments
 (0)