Skip to content

Conversation

@TamarZanzouri
Copy link
Contributor

@TamarZanzouri TamarZanzouri commented Dec 3, 2025

Overview

part of https://opentrons.atlassian.net/browse/EXEC-1445 to unblock stacker form work.

Test Plan and Hands on Testing

  • added unit tests to test logic for labware details + able to test this by using stoybook
Screenshot 2025-12-03 at 12 26 20 PM Screenshot 2025-12-02 at 9 24 00 PM Screenshot 2025-12-02 at 9 24 07 PM

Changelog

  • extract labawreDetailsWithQuantity to shared components
  • added flexStacker step
  • added form skeleton for stacker
  • added logic for labware details on shuttle/stacker

Review requests

  1. naming make sense?
  2. is this good for a first pase?

Risk assessment

low. adding a new step form for flex stacker.

@TamarZanzouri TamarZanzouri requested a review from a team as a code owner December 3, 2025 02:58
@TamarZanzouri TamarZanzouri requested review from jerader and ncdiehl11 and removed request for a team December 3, 2025 02:59
@@ -39,6 +61,7 @@
"camera": {
"capture_image": "Capture image of the deck"
},
"flexStacker": "Flex Stacker",
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes! this is the step map! i left a comment about this. not sure how we want to deal with this

Comment on lines 540 to 541
{/* TODO: how can we use json key names instead of stepType?*/}
{t(`protocol_steps:${formData.stepType}`)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

i led you astray here, sorry!!!! we need to be displaying the stepName because that's what the step rename selector is displaying. So for now, can you actually keep using capitalizeFirstLetter() and add a case for flex stacker? we can go back and refactor the function later.

Screen.Recording.2025-12-03.at.06.50.32.mov

Copy link
Collaborator

@jerader jerader left a comment

Choose a reason for hiding this comment

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

nice! a bunch of stuff needs to be adding to css modules 😭 and left a few other comments.

Copy link
Collaborator

@ncdiehl11 ncdiehl11 left a comment

Choose a reason for hiding this comment

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

first pass of feedback!

Comment on lines +183 to +197
<RadioButton
buttonValue="retrieve"
disabled={labwareInHopperCount === 0 || labwareOnShuttle != null}
buttonLabel={
<StyledText desktopStyle="bodyDefaultRegular">Retrieve</StyledText>
}
buttonSubLabel={{
align: 'vertical',
label: t(
'protocol_steps:flex_stacker.module_controls.retrieve_sublabel'
),
}}
onChange={() => {}}
largeDesktopBorderRadius
/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

This button has to be dynamic depending on if there's labware on the shuttle or not right? Maybe we should move the radio button logic to a hook that will take the robot state and return the radio button options

@@ -251,6 +251,14 @@ export function getDefaultsForStepType(
referenceWavelengthActive: false,
wavelengths: [Object.keys(ABSORBANCE_READER_COLOR_BY_WAVELENGTH)[0]], // default to first known wavelength
}
case 'flexStacker':
return {
Copy link
Collaborator

Choose a reason for hiding this comment

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

i forgot where we landed on this but didn't we discuss having something like flexStackerFormType akin to the absorbance reader form type?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

was planning on implementing this as part of the command implementation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

left a comment about not being fully flushed

@@ -498,6 +501,12 @@ export interface HydratedAbsorbanceReaderFormData extends AnnotationFields {
wavelengths: string[]
}

export interface HydratedFlexStackerFormData extends AnnotationFields {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we're missing fields here. This should include the types of all the properties in protocol-designer/src/steplist/formLevel/getDefaultsForStepType.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

left a comment about not being fully flushed

@@ -112,6 +112,7 @@ export interface FlexStackerModuleState {
type: typeof FLEX_STACKER_MODULE_TYPE
maxPoolCount: number
storedLabwareDetails: FlexStackerSetStoredLabwareParams | null
// labware in hopper is the bottom up
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

Copy link
Collaborator

@ncdiehl11 ncdiehl11 left a comment

Choose a reason for hiding this comment

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

i left a couple of cleanup comments, but once those are addressed and checks pass, I think this is good to merge!! 🚀

justify-content: space-between;
}

div.container {
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we need div here since we're adding these styles to a div in the component?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so I added the div bc the I wanted to make sure that this class is being appended to a div but its also a local css file so its not really a MUST

gap: var(--spacing-8);
}

div.container.padding_x {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same

Comment on lines +540 to +543
{/* TODO: use module object from form.json instead */}
{formData.stepType === 'flexStacker'
? t(`protocol_steps:${formData.stepType}`)
: capitalizeFirstLetter(String(formData.stepName))}
Copy link
Collaborator

Choose a reason for hiding this comment

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

sorry why do we need to special case the stacker? it could be right I am just not following

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we want to move away from capitalizeFirstLetter and use the step type as the key in a translation file. so instead of special casing this in capitalizeFirstLetter I special cased it here.

@TamarZanzouri TamarZanzouri merged commit a102faf into edge Dec 5, 2025
49 of 50 checks passed
@TamarZanzouri TamarZanzouri deleted the EXEC-1445-add-a-stacker-step-to-the-protocol branch December 5, 2025 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants