Skip to content

Commit

Permalink
feat(app): add fixture list view on desktop (#13719)
Browse files Browse the repository at this point in the history
closes RAUT-694
  • Loading branch information
jerader authored Oct 6, 2023
1 parent 03668be commit 1b209e5
Show file tree
Hide file tree
Showing 20 changed files with 570 additions and 97 deletions.
2 changes: 1 addition & 1 deletion api-client/src/protocols/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export function parseInitialLoadedModulesBySlot(
)
}

interface LoadedFixturesBySlot {
export interface LoadedFixturesBySlot {
[slotName: string]: LoadFixtureRunTimeCommand
}
export function parseInitialLoadedFixturesByCutout(
Expand Down
Binary file added app/src/assets/images/staging_area_slot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions app/src/assets/localization/en/protocol_setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@
"extra_attention_warning_title": "Secure labware and modules before proceeding to run",
"extra_module_attached": "Extra module attached",
"feedback_form_link": "Let us know!",
"fixture_name": "fixture",
"get_labware_offset_data": "Get Labware Offset Data",
"heater_shaker_extra_attention": "Use latch controls for easy placement of labware.",
"heater_shaker_labware_list_view": "To add labware, use the toggle to control the latch",
"how_offset_data_works": "How labware offsets work",
"initial_liquids_num_plural": "{{count}} initial liquids",
"initial_liquids_num": "{{count}} initial liquid",
"initial_location": "Initial Location",
"install_modules_and_fixtures": "Install the required modules and power them on. Install the required fixtures and review the deck configuration.",
"instruments_connected_plural": "{{count}} instruments attached",
"instruments_connected": "{{count}} instrument attached",
"instruments": "Instruments",
Expand Down Expand Up @@ -104,11 +106,12 @@
"missing": "Missing",
"modal_instructions_title": "{{moduleName}} Setup Instructions",
"modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.",
"module_and_deck_setup": "Modules & deck",
"module_connected": "Connected",
"module_disconnected": "Disconnected",
"module_instructions_link": "{{moduleName}} setup instructions",
"module_mismatch_body": "Check that the modules connected to this robot are of the right type and generation",
"module_name": "Module Name",
"module_name": "Module",
"module_not_connected": "Not connected",
"module_setup_step_description_plural": "Install the required modules and power them on.",
"module_setup_step_description": "Install the required modules and power them on.",
Expand All @@ -132,6 +135,7 @@
"n_a": "N/A",
"no_data": "no data",
"no_labware_offset_data": "no labware offset data yet",
"no_modules_or_fixtures": "No modules or fixtures are specified for this protocol.",
"no_modules_specified": "no modules are specified for this protocol.",
"no_modules_used_in_this_protocol": "No modules used in this protocol",
"no_tiprack_loaded": "Protocol must load a tip rack",
Expand Down Expand Up @@ -214,8 +218,9 @@
"usb_port_connected": "USB Port {{port}}",
"view_current_offsets": "View current offsets",
"view_moam": "View setup instructions for placing modules of the same type to the robot.",
"view_module_setup_instructions": "View module setup instructions",
"view_setup_instructions": "View setup instructions",
"volume": "Volume",
"update_deck": "Update deck",
"what_labware_offset_is": "A Labware Offset is a type of positional adjustment that accounts for small, real-world variances in the overall position of the labware on a robot’s deck. Labware Offset data is unique to a specific combination of labware definition, deck slot, and robot.",
"why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration."
}
148 changes: 106 additions & 42 deletions app/src/organisms/Devices/ProtocolRun/ProtocolRunSetup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'

import { parseAllRequiredModuleModels } from '@opentrons/api-client'
import {
LoadedFixturesBySlot,
parseAllRequiredModuleModels,
} from '@opentrons/api-client'
import {
Flex,
ALIGN_CENTER,
Expand All @@ -14,9 +17,14 @@ import {
TYPOGRAPHY,
Link,
} from '@opentrons/components'
import {
STAGING_AREA_LOAD_NAME,
WASTE_CHUTE_LOAD_NAME,
} from '@opentrons/shared-data'

import { Line } from '../../../atoms/structure'
import { StyledText } from '../../../atoms/text'
import { useFeatureFlag } from '../../../redux/config'
import { InfoMessage } from '../../../molecules/InfoMessage'
import {
useIsOT3,
Expand All @@ -31,7 +39,7 @@ import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMo
import { SetupLabware } from './SetupLabware'
import { SetupLabwarePositionCheck } from './SetupLabwarePositionCheck'
import { SetupRobotCalibration } from './SetupRobotCalibration'
import { SetupModules } from './SetupModules'
import { SetupModuleAndDeck } from './SetupModuleAndDeck'
import { SetupStep } from './SetupStep'
import { SetupLiquids } from './SetupLiquids'
import { EmptySetupStep } from './EmptySetupStep'
Expand Down Expand Up @@ -66,6 +74,40 @@ export function ProtocolRunSetup({
const storedProtocolAnalysis = useStoredProtocolAnalysis(runId)
const protocolData = robotProtocolAnalysis ?? storedProtocolAnalysis
const modules = parseAllRequiredModuleModels(protocolData?.commands ?? [])
const enableDeckConfig = useFeatureFlag('enableDeckConfiguration')
// TODO(Jr, 10/4/23): stubbed in the fixtures for now - delete IMMEDIATELY
// const loadedFixturesBySlot = parseInitialLoadedFixturesByCutout(
// protocolData?.commands ?? []
// )

const STUBBED_LOAD_FIXTURE_BY_SLOT: LoadedFixturesBySlot = {
D3: {
id: 'stubbed_load_fixture',
commandType: 'loadFixture',
params: {
fixtureId: 'stubbedFixtureId',
loadName: WASTE_CHUTE_LOAD_NAME,
location: { cutout: 'D3' },
},
createdAt: 'fakeTimestamp',
startedAt: 'fakeTimestamp',
completedAt: 'fakeTimestamp',
status: 'succeeded',
},
B3: {
id: 'stubbed_load_fixture_2',
commandType: 'loadFixture',
params: {
fixtureId: 'stubbedFixtureId_2',
loadName: STAGING_AREA_LOAD_NAME,
location: { cutout: 'B3' },
},
createdAt: 'fakeTimestamp',
startedAt: 'fakeTimestamp',
completedAt: 'fakeTimestamp',
status: 'succeeded',
},
}
const robot = useRobot(robotName)
const calibrationStatus = useRunCalibrationStatus(robotName, runId)
const isOT3 = useIsOT3(robotName)
Expand Down Expand Up @@ -111,6 +153,19 @@ export function ProtocolRunSetup({
if (robot == null) return null
const hasLiquids = protocolData != null && protocolData.liquids?.length > 0
const hasModules = protocolData != null && modules.length > 0
const hasFixtures =
protocolData != null && Object.keys(STUBBED_LOAD_FIXTURE_BY_SLOT).length > 0

let moduleDescription: string = t(`${MODULE_SETUP_KEY}_description`, {
count: modules.length,
})
if (!hasModules && !enableDeckConfig) {
moduleDescription = i18n.format(t('no_modules_specified'), 'capitalize')
} else if (isOT3 && enableDeckConfig && (hasModules || hasFixtures)) {
moduleDescription = t('install_modules_and_fixtures')
} else if (isOT3 && enableDeckConfig && !hasModules && !hasFixtures) {
moduleDescription = t('no_modules_or_fixtures')
}

const StepDetailMap: Record<
StepKey,
Expand Down Expand Up @@ -139,17 +194,15 @@ export function ProtocolRunSetup({
},
[MODULE_SETUP_KEY]: {
stepInternals: (
<SetupModules
<SetupModuleAndDeck
expandLabwarePositionCheckStep={() => setExpandedStepKey(LPC_KEY)}
robotName={robotName}
runId={runId}
loadedFixturesBySlot={STUBBED_LOAD_FIXTURE_BY_SLOT}
hasModules={hasModules}
/>
),
description: !hasModules
? i18n.format(t('no_modules_specified'), 'capitalize')
: t(`${MODULE_SETUP_KEY}_description`, {
count: modules.length,
}),
description: moduleDescription,
},
[LPC_KEY]: {
stepInternals: (
Expand Down Expand Up @@ -207,40 +260,51 @@ export function ProtocolRunSetup({
{t('protocol_analysis_failed')}
</StyledText>
) : (
stepsKeysInOrder.map((stepKey, index) => (
<Flex flexDirection={DIRECTION_COLUMN} key={stepKey}>
{(stepKey === 'liquid_setup_step' && !hasLiquids) ||
(stepKey === 'module_setup_step' && !hasModules) ? (
<EmptySetupStep
title={t(`${stepKey}_title`)}
description={StepDetailMap[stepKey].description}
label={t('step', { index: index + 1 })}
/>
) : (
<SetupStep
expanded={stepKey === expandedStepKey}
label={t('step', { index: index + 1 })}
title={t(`${stepKey}_title`)}
description={StepDetailMap[stepKey].description}
toggleExpanded={() =>
stepKey === expandedStepKey
? setExpandedStepKey(null)
: setExpandedStepKey(stepKey)
}
rightElement={
<StepRightElement
{...{ stepKey, runHasStarted, calibrationStatus }}
/>
}
>
{StepDetailMap[stepKey].stepInternals}
</SetupStep>
)}
{index !== stepsKeysInOrder.length - 1 ? (
<Line marginTop={SPACING.spacing24} />
) : null}
</Flex>
))
stepsKeysInOrder.map((stepKey, index) => {
const setupStepTitle = t(
isOT3 && stepKey === MODULE_SETUP_KEY && enableDeckConfig
? `module_and_deck_setup`
: `${stepKey}_title`
)
const showEmptySetupStep =
(stepKey === 'liquid_setup_step' && !hasLiquids) ||
(stepKey === 'module_setup_step' &&
((!enableDeckConfig && !hasModules) ||
(enableDeckConfig && !hasModules && !hasFixtures)))
return (
<Flex flexDirection={DIRECTION_COLUMN} key={stepKey}>
{showEmptySetupStep ? (
<EmptySetupStep
title={t(`${stepKey}_title`)}
description={StepDetailMap[stepKey].description}
label={t('step', { index: index + 1 })}
/>
) : (
<SetupStep
expanded={stepKey === expandedStepKey}
label={t('step', { index: index + 1 })}
title={setupStepTitle}
description={StepDetailMap[stepKey].description}
toggleExpanded={() =>
stepKey === expandedStepKey
? setExpandedStepKey(null)
: setExpandedStepKey(stepKey)
}
rightElement={
<StepRightElement
{...{ stepKey, runHasStarted, calibrationStatus }}
/>
}
>
{StepDetailMap[stepKey].stepInternals}
</SetupStep>
)}
{index !== stepsKeysInOrder.length - 1 ? (
<Line marginTop={SPACING.spacing24} />
) : null}
</Flex>
)
})
)}
</>
) : (
Expand Down
Loading

0 comments on commit 1b209e5

Please sign in to comment.