Skip to content

Conversation

@jerader
Copy link
Collaborator

@jerader jerader commented Dec 8, 2025

closes EXEC-1441 EXEC-1443

Overview

Hopper was tired of waiting.
hopper

With this PR, you can add labware to the hopper in PD! There is now a hoverable slot over the hopper location and you can add labware to it. The labware entity gets created with the location stack as: [labwareId, hopper, moduleId, slot]

Additionally, since the stacker covers 1 slot but visually is 2 slots, i had to fake the hopper slots. So i created this map:

export const HOPPER_FAKE_LOCATIONS = [
  'hopperA4',
  'hopperB4',
  'hopperC4',
  'hopperD4',
]

the hopper locations are now referred to as those ^. there is a util i made to easily decipher if the slot is a hopper location or not using getIsSlotAHopper() which takes in a slot arg.

the labwareLocationUpdate structure is the same but to differentiate between a labwareon the hopper vs the shuttle, the shuttle labware locaiton simply shows the slot name and not the module id. So like this

{
  'f29fef4f-2724-4144-b1ef-aadd689662dd:opentrons/biorad_384_wellplate_50ul/4':
    'B4',
  '10bac4a0-6406-412e-aa2e-352ea85825d8:opentrons/opentrons_flex_96_tiprack_50ul/1':
    '3e97d575-64d3-402b-a1e9-0e6bf2a0a9a6:flexStackerModuleType',
}

the biorad is on the shuttle and the other labware is on the hopper.

Some follow-ups that I will work on:

  1. Add all the svg layer labels for stacker: ActiveLabwareControls, highlightItems, highlightLabware
  2. Fix the selectLabwareModal to properly show adding a stack
  3. Don’t allow dragging/dropping into hopper or shuttle
  4. audit the labware dropdowns for transfer, mix and move labware to be correct and not include hopper labware or shuttle labware if its a pipetting step

Test Plan and Hands on Testing

Add a stacker to the deck in the onboarding wizard (there is a bug if you add it after the fact that i need to document still in a ticket)

Then see that you can hover over the hopper and add labware.

also import an older version of PD made in prod and see that it imports without any issues since there is a migration

Changelog

add new fake hopper locations, plugging stuff into the PD deck map

Risk assessment

low

@codecov
Copy link

codecov bot commented Dec 8, 2025

Codecov Report

❌ Patch coverage is 33.03571% with 150 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.05%. Comparing base (a102faf) to head (d77423d).
⚠️ Report is 5 commits behind head on edge.

Files with missing lines Patch % Lines
.../src/pages/Designer/DeckSetup/DeckSetupDetails.tsx 0.00% 65 Missing ⚠️
protocol-designer/src/utils/index.ts 29.72% 26 Missing ⚠️
...rc/pages/ProtocolOverview/DeckThumbnailDetails.tsx 0.00% 16 Missing ⚠️
.../src/pages/Designer/DeckSetup/DeckSetupToolbox.tsx 23.07% 10 Missing ⚠️
...rc/pages/Designer/DeckSetup/DeckSetupContainer.tsx 0.00% 8 Missing ⚠️
...pages/Designer/DeckSetup/Overlays/SlotControls.tsx 0.00% 6 Missing ⚠️
...omponents/organisms/SlotDetailsContainer/index.tsx 0.00% 5 Missing ⚠️
...src/components/organisms/SlotInformation/index.tsx 44.44% 5 Missing ⚠️
protocol-designer/src/pages/Designer/utils.ts 61.53% 5 Missing ⚠️
...rotocol-designer/src/step-forms/selectors/index.ts 0.00% 3 Missing ⚠️
... and 1 more
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             edge   #20316       +/-   ##
===========================================
+ Coverage   25.83%   57.05%   +31.21%     
===========================================
  Files        3627     3628        +1     
  Lines      302041   302357      +316     
  Branches    42320    42545      +225     
===========================================
+ Hits        78020   172495    +94475     
+ Misses     223992   129634    -94358     
- Partials       29      228      +199     
Flag Coverage Δ
app 46.20% <8.48%> (+45.04%) ⬆️
protocol-designer 19.35% <33.03%> (+<0.01%) ⬆️
step-generation 5.59% <8.03%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
protocol-designer/src/constants.ts 69.78% <100.00%> (+0.33%) ⬆️
...ocol-designer/src/labware-ingred/actions/thunks.ts 27.27% <ø> (+0.11%) ⬆️
...er/src/pages/Designer/DeckSetup/HighlightItems.tsx 4.64% <ø> (+0.01%) ⬆️
.../src/pages/Designer/DeckSetup/SlotOverflowMenu.tsx 51.97% <ø> (+0.17%) ⬆️
protocol-designer/src/step-forms/actions/thunks.ts 8.77% <ø> (+0.15%) ⬆️
protocol-designer/src/step-forms/reducers/index.ts 39.89% <100.00%> (+0.25%) ⬆️
protocol-designer/src/step-forms/utils/index.ts 61.87% <100.00%> (ø)
shared-data/js/fixtures.ts 88.62% <100.00%> (+9.45%) ⬆️
step-generation/src/constants.ts 98.68% <100.00%> (+0.24%) ⬆️
step-generation/src/utils/misc.ts 61.48% <100.00%> (+0.09%) ⬆️
... and 11 more

... and 1848 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jerader jerader changed the title feat(protocol-designer): the labware belongs in the hopper, so I put it there feat(protocol-designer): the labware belongs on the hopper, so I put it there Dec 8, 2025
@jerader jerader requested a review from ddcc4 December 8, 2025 17:09
@jerader jerader marked this pull request as ready for review December 8, 2025 17:54
@jerader jerader requested a review from a team as a code owner December 8, 2025 17:54
@jerader jerader requested review from TamarZanzouri and ncdiehl11 and removed request for a team December 8, 2025 17:54
: TC_MODULE_LOCATION_OT2
const modifiedLocation =

let modifiedLocation = location
Copy link
Contributor

Choose a reason for hiding this comment

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

I know that in the app we are trying to move away from using let

const id = `${uuid()}:${labwareUri}`
const labwareDef =
labwareDefSelectors.getLabwareDefsByURI(state)[labwareUri]

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

}, '')

const addEquipment = (slotId: string): void => {
const isOnHopper = slotId.includes('hopper')
Copy link
Contributor

Choose a reason for hiding this comment

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

can we rename slotId? its no longer a slot right?


const addEquipment = (slotId: string): void => {
const isOnHopper = slotId.includes('hopper')
const slot = isOnHopper ? slotId.split('hopper')[1] : slotId
Copy link
Contributor

Choose a reason for hiding this comment

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

lets call it aa instead of slot

rightBelowTopId: string | null
hopperTopMostId: string | null
} => {
// all stacks involving this module
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// all stacks involving this module
// all stacks involving this module except hopper location

lw =>
lw.stack.includes(moduleId) && lw.stack.includes(HOPPER_STACKER_LOCATION)
)
const largestStackOnHopper = allStacksOnHopper.sort(
Copy link
Contributor

Choose a reason for hiding this comment

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

nice! do we need to do this bc every labware in the stack has a stack of its own?


export const HOPPER_STACKER_LOCATION = 'hopper'

export const HOPPER_FAKE_LOCATIONS = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice!

'hopperD4',
]

export const HOPPER_LOCATION_MAP = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export const HOPPER_LOCATION_MAP = {
export const FAKE_HOPPER_LOCATION_MAP = {

latestDefs
)
acc[updatedLabwareId] = location

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

Copy link
Contributor

@TamarZanzouri TamarZanzouri left a comment

Choose a reason for hiding this comment

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

overall looks great! thank you for doing this! had a few comments

const moduleOnSlot = Object.values(deckSetupModules).find(
module => module.slot === slot
module =>
module.slot === slot || (slot.includes(module.slot) && isSlotAHopper)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the includes() for? What value does slot have such that you would need includes() to search for a substring?

@ddcc4
Copy link
Collaborator

ddcc4 commented Dec 8, 2025

Wait a second ... I thought we said that the shuttle was conceptually in A4...D4, not the hopper?

Do you want the fake hopper location to be hopperA5? Or just hopperA if that's too confusing?

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