Skip to content

Commit

Permalink
feat(protocol-designer, step-generation): timeline warnings and error… (
Browse files Browse the repository at this point in the history
#16566)

…s revamp

closes AUTH-889
  • Loading branch information
jerader authored Oct 23, 2024
1 parent 7ae1d56 commit 42699e3
Show file tree
Hide file tree
Showing 25 changed files with 342 additions and 273 deletions.
90 changes: 48 additions & 42 deletions protocol-designer/src/assets/localization/en/alert.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,122 +97,128 @@
"timeline": {
"error": {
"LABWARE_DISCARDED_IN_WASTE_CHUTE": {
"title": "The labware has been previously discarded into the waste chute",
"body": "Please select a different labware to move."
"title": "Labware not available",
"body": "This step uses labware that has previously been discarded into a Waste Chute."
},
"LABWARE_ON_ANOTHER_ENTITY": {
"title": "Attempting to move a labware on top of another entity",
"title": "Attempting to move labware on top of another entity",
"body": "Please reselect which slot your labware should move to."
},
"INSUFFICIENT_TIPS": {
"title": "Not enough tips to complete action",
"body": "Add another tip rack to an empty slot in "
"body": "Add another tip rack to your deck or change your tip management during transfer and mix steps.",
"link": "Edit starting deck"
},
"NO_TIP_SELECTED": {
"title": "No tip rack was selected to complete action",
"body": "Add a tip rack in the step"
},
"NO_TIP_ON_PIPETTE": {
"title": "No tip on pipette at the start of step",
"body1": "Choose a different Change Tip setting. Change Tip cannot be \"Never\" the first time a pipette is used in a protocol, or following a step that used the ",
"link": "Air gap dispense setting",
"body2": ". Pipetting steps must begin with a tip on."
"title": "No tip on pipette at start of step",
"body": "Use a different tip handling setting. Don't set it to Never the first time a pipette is used in a protocol, or following a step that air gaps when dispensing."
},
"MODULE_PIPETTE_COLLISION_DANGER": {
"title": "Pipette cannot access labware",
"body": "Gen 1 8-Channel pipettes cannot access labware or tip racks in slot 4 or 6 because they are adjacent to modules. Read more "
"title": "GEN1 8-Channel Pipettes can't move adjacent to modules",
"body": "Move labware and modules or use a different pipette."
},
"MISSING_MODULE": {
"title": "Missing module for step",
"body": "A step requires a module that does not exist"
"title": "Module not in protocol",
"body": "This step tries to use a module not in the protocol. Add the module to your protocol or remove this step."
},
"MISSING_TEMPERATURE_STEP": {
"title": "Missing Temperature step",
"body": "Add a Temperature step prior to this Pause step. The module is not currently changing temperature because it has either been deactivated or is holding a temperature"
"title": "Unreachable target temperature",
"body": "The protocol can't proceed beyond this pause step, because the module is not changing temperature. Add or modify a temperature step before this step."
},
"THERMOCYCLER_LID_CLOSED": {
"title": "Thermocycler lid is closed",
"body": "Before the robot can interact with labware in the Thermocycler, the lid must be open. To resolve this error, please add a thermocycler step ahead of the current step, and set the lid status to \"open\"."
"title": "Thermocycler lid closed",
"body": "This step tries to use labware in the Thermocycler. Open the lid before this step."
},
"HEATER_SHAKER_LATCH_OPEN": {
"title": "Heater-Shaker labware latch is open",
"title": "Heater-Shaker latch open",
"body": "Before the robot can interact with labware on the Heater-Shaker module, the labware latch must be closed. To resolve this error, please add a Heater-Shaker step ahead of the current step, and set the labware latch status to \"closed\"."
},
"HEATER_SHAKER_IS_SHAKING": {
"title": "Heater-Shaker is shaking",
"body": "the robot cannot interact with labware on the Heater-Shaker Module while it is shaking."
"body": "The robot cannot interact with labware on the Heater-Shaker Module while it is shaking. Add a step to stop shaking to interact with the labware."
},
"TALL_LABWARE_EAST_WEST_OF_HEATER_SHAKER": {
"body": "The Heater-Shaker labware latch will collide with labware over 53 mm. Move labware to a different slot."
},
"HEATER_SHAKER_EAST_WEST_LATCH_OPEN": {
"title": "Heater-Shaker labware latch open",
"body": "Pipettes cannot access labware on, or to the left or right of, the Heater-Shaker while the labware latch is open. Create a step before this one that closes the latch."
},
"HEATER_SHAKER_NORTH_SOUTH_EAST_WEST_SHAKING": {
"title": "The Heater-Shaker is shaking",
"body": "Pipettes cannot access labware on or adjacent to the Heater-Shaker while it is shaking. Create a step before this one that deactivates the shaker."
"title": "Robot unable to perform step",
"body": "The robot cannot interact with labware on or next to the Heater-Shaker Module while it is shaking. Add a heater-shaker step to stop shaking."
},
"HEATER_SHAKER_EAST_WEST_MULTI_CHANNEL": {
"title": "8-Channel pipette cannot access labware",
"body": "8-Channel pipettes cannot access labware or tip racks to the left or right of a Heater-Shaker GEN1 module. Move labware to a different slot to access it with an 8-Channel pipette."
"title": "8-Channel unable to access slot",
"body": "8-Channel pipettes cannot access labware to the left or right of a Heater-Shaker GEN1 module. Move labware to a different slot to access it with an 8-Channel pipette."
},
"HEATER_SHAKER_NORTH_SOUTH__OF_NON_TIPRACK_WITH_MULTI_CHANNEL": {
"title": "8-Channel pipette cannot access labware",
"body": "8-Channel pipettes cannot access labware in front of or behind a Heater-Shaker. They can access Opentrons Tip Racks in this slot. Move labware to a different slot."
"title": "8-Channel unable to access slot",
"body": "8-Channel pipettes cannot access non-tiprack labware to the top or bottom of a Heater-Shaker GEN1 module. Move labware to a different slot to access it with an 8-Channel pipette."
},
"LABWARE_OFF_DECK": {
"title": "Labware is off-deck",
"title": "Labware not on deck",
"body": "The robot can only perform steps on labware that is on the deck. Add or change a Move Labware step to put it on the deck before this step."
},
"HEATER_SHAKER_LATCH_CLOSED": {
"title": "Heater-Shaker labware latch is closed",
"title": "Heater-Shaker latch closed",
"body": "The Heater-Shaker’s labware latch must be open when moving labware to or from the module. Add a Heater-Shaker step that opens the latch before this step."
},
"DROP_TIP_LOCATION_DOES_NOT_EXIST": {
"title": "Attempting to drop tip in an unknown location",
"body": "The Waste Chute or Trash Bin to drop tip in does not exist."
},
"MISSING_96_CHANNEL_TIPRACK_ADAPTER": {
"title": "Missing 96-channel tip rack adapter",
"body": "The tip rack must be placed in an adapter when picking up 96 tips simultaneously."
"title": "Tip rack adapter required",
"body": "The 96-channel pipette uses a tip rack adapter to pick up a full rack of tips. Add one to your starting deck or use partial tip pickup.",
"link": "Edit starting deck"
},
"EQUIPMENT_DOES_NOT_EXIST": {
"title": "Attempting to interact with an unknown entity",
"title": "Unable to perform step",
"body": "An entity you are interacting with does not exist."
},
"GRIPPER_REQUIRED": {
"title": "A gripper is required to complete this action",
"body": "Attempting to move a labware without a gripper into the waste chute. Please add a gripper to this step."
"title": "Cannot move with gripper",
"body": "The gripper cannot move aluminum blocks. Deselect the 'Use Gripper' checkbox."
},
"REMOVE_96_CHANNEL_TIPRACK_ADAPTER": {
"title": "Do not use tip rack adapter for partial tip pickup",
"body": "Partial tip pickup requires a tip rack placed directly on the deck. Remove the adapter, or add a new tip rack without an adapter."
"title": "Extra tip rack adapter",
"body": "When picking up fewer than 96 tips, the tip rack must be placed directly on the deck, not in the tip rack adapter.",
"link": "Edit starting deck"
},
"CANNOT_MOVE_WITH_GRIPPER": {
"title": "Cannot move with gripper",
"body": "The gripper cannot move aluminum blocks. Edit the step and deselect the 'Use Gripper' checkbox."
},
"PIPETTE_HAS_TIP": {
"title": "Possible collision with tip",
"body": "The gripper cannot pick up labware while pipettes have tips attached. Drop all tips before this move labware step."
"title": "Gripper movement with tips attached",
"body": "Picking up labware with the gripper while tips are on an adjacent pipette can cause collisions. Drop tips from all pipettes before this step."
},
"POSSIBLE_PIPETTE_COLLISION": {
"title": "Pipette collisions likely",
"body": "There is a possibility that the pipette will collide with the adjascent labware or module for partial tip pick up."
}
},
"warning": {
"ASPIRATE_MORE_THAN_WELL_CONTENTS": {
"title": "Not enough liquid in well(s)",
"body": "You are trying to aspirate more than the current volume of one of your well(s)"
"title": "Not enough liquid",
"body": "This step tries to aspirate more than the current volume of a source well."
},
"ASPIRATE_FROM_PRISTINE_WELL": {
"title": "Source well is empty",
"body": "The well(s) you're trying to aspirate from are empty. To add liquids, hover over labware in "
"body": "This step tries to aspirate from an empty well."
},
"LABWARE_IN_WASTE_CHUTE_HAS_LIQUID": {
"title": "Moving labware into waste chute",
"body": "This labware has remaining liquid, be advised that once you dispose of it, there is no way to get it back later in the protocol."
"title": "Disposing liquid-filled labware",
"body": "This step moves a labware that contains liquid to the waste chute. There is no way to retrieve the liquid after disposal."
},
"TIPRACK_IN_WASTE_CHUTE_HAS_TIPS": {
"title": "Moving tiprack into waste chute",
"body": "This tiprack has remaining tips, be advised that once you dispose of it, there is no way to get it back later in the protocol. "
"title": "Disposing unused tips",
"body": "This step moves a tip rack that contains unused tips to the waste chute. There is no way to retrieve the tips after disposal."
}
}
},
Expand Down
17 changes: 16 additions & 1 deletion protocol-designer/src/file-data/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { FileMetadataFields, SaveFileMetadataAction } from './types'
import type {
FileMetadataFields,
SaveFileMetadataAction,
SelectDesignerTabAction,
} from './types'
import type { WorkerResponse } from '../timelineMiddleware/types'
export const saveFileMetadata = (
payload: FileMetadataFields
Expand All @@ -22,3 +26,14 @@ export const computeRobotStateTimelineSuccess = (
type: 'COMPUTE_ROBOT_STATE_TIMELINE_SUCCESS',
payload,
})

export interface DesignerTabPayload {
tab: 'protocolSteps' | 'startingDeck'
}

export const selectDesignerTab = (
payload: DesignerTabPayload
): SelectDesignerTabAction => ({
type: 'SELECT_DESIGNER_TAB',
payload,
})
25 changes: 23 additions & 2 deletions protocol-designer/src/file-data/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ import type { RobotType } from '@opentrons/shared-data'
import type { Action } from '../../types'
import type { LoadFileAction, NewProtocolFields } from '../../load-file'
import type { Substeps } from '../../steplist/types'
import type { ComputeRobotStateTimelineSuccessAction } from '../actions'
import type { FileMetadataFields, SaveFileMetadataAction } from '../types'
import type {
ComputeRobotStateTimelineSuccessAction,
DesignerTabPayload,
} from '../actions'
import type {
FileMetadataFields,
SaveFileMetadataAction,
SelectDesignerTabAction,
} from '../types'

export const timelineIsBeingComputed: Reducer<boolean, any> = handleActions(
{
Expand Down Expand Up @@ -110,13 +117,26 @@ const robotTypeReducer = (
}
return state
}

const designerTabReducer = (
state: DesignerTabPayload['tab'] = 'startingDeck',
action: SelectDesignerTabAction
): DesignerTabPayload['tab'] => {
if (action.type === 'SELECT_DESIGNER_TAB') {
return action.payload.tab
} else {
return state
}
}

export interface RootState {
computedRobotStateTimeline: Timeline
computedSubsteps: Substeps
currentProtocolExists: boolean
fileMetadata: FileMetadataFields
timelineIsBeingComputed: boolean
robotType: RobotType
designerTab: DesignerTabPayload['tab']
}
const _allReducers = {
computedRobotStateTimeline,
Expand All @@ -125,6 +145,7 @@ const _allReducers = {
fileMetadata,
timelineIsBeingComputed,
robotType: robotTypeReducer,
designerTab: designerTabReducer,
}
export const rootReducer: Reducer<RootState, Action> = combineReducers(
_allReducers
Expand Down
5 changes: 5 additions & 0 deletions protocol-designer/src/file-data/selectors/fileFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { BaseState, Selector } from '../../types'
import type { RootState } from '../reducers'
import type { FileMetadataFields } from '../types'
import type { RobotType } from '@opentrons/shared-data'
import type { DesignerTabPayload } from '../actions'

export const rootSelector = (state: BaseState): RootState => state.fileData
export const getCurrentProtocolExists: Selector<boolean> = createSelector(
Expand All @@ -21,3 +22,7 @@ export const getRobotType: Selector<RobotType> = createSelector(
rootSelector,
state => state.robotType
)

export const getDesignerTab: Selector<
DesignerTabPayload['tab']
> = createSelector(rootSelector, state => state.designerTab)
6 changes: 6 additions & 0 deletions protocol-designer/src/file-data/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import type { ProtocolFile } from '@opentrons/shared-data'
import type { DesignerTabPayload } from './actions'
export type FileMetadataFields = ProtocolFile<{}>['metadata']
export type FileMetadataFieldAccessors = keyof FileMetadataFields
export interface SaveFileMetadataAction {
type: 'SAVE_FILE_METADATA'
payload: FileMetadataFields
}

export interface SelectDesignerTabAction {
type: 'SELECT_DESIGNER_TAB'
payload: DesignerTabPayload
}
65 changes: 43 additions & 22 deletions protocol-designer/src/organisms/Alerts/ErrorContents.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { useTranslation } from 'react-i18next'
import { START_TERMINAL_ITEM_ID } from '../../steplist'
import { KnowledgeBaseLink } from '../../components/KnowledgeBaseLink'
import { TerminalItemLink } from './TerminalItemLink'
import { useDispatch } from 'react-redux'
import {
Btn,
Flex,
JUSTIFY_SPACE_BETWEEN,
SPACING,
TYPOGRAPHY,
} from '@opentrons/components'
import { BUTTON_LINK_STYLE } from '../../atoms'
import { selectDesignerTab } from '../../file-data/actions'

import type { AlertLevel } from './types'

Expand All @@ -14,6 +21,7 @@ export const ErrorContents = (
): JSX.Element | null => {
const { errorType, level } = props
const { t } = useTranslation(['alert', 'shared'])
const dispatch = useDispatch()

if (level === 'timeline') {
const bodyText = t(`timeline.error.${errorType}.body`, {
Expand All @@ -22,29 +30,42 @@ export const ErrorContents = (
switch (errorType) {
case 'INSUFFICIENT_TIPS':
return (
<>
<Flex
justifyContent={JUSTIFY_SPACE_BETWEEN}
gridGap={SPACING.spacing8}
>
{bodyText}
<TerminalItemLink terminalId={START_TERMINAL_ITEM_ID} />
</>
)
case 'MODULE_PIPETTE_COLLISION_DANGER':
return (
<>
{bodyText}
<KnowledgeBaseLink to="pipetteGen1MultiModuleCollision">
{t('shared:here')}
</KnowledgeBaseLink>
</>
<Btn
width="7.25rem"
textDecoration={TYPOGRAPHY.textDecorationUnderline}
css={BUTTON_LINK_STYLE}
onClick={() => {
dispatch(selectDesignerTab({ tab: 'startingDeck' }))
}}
>
{t(`timeline.error.${errorType}.link`)}
</Btn>
</Flex>
)
case 'NO_TIP_ON_PIPETTE':
case 'REMOVE_96_CHANNEL_TIPRACK_ADAPTER':
case 'MISSING_96_CHANNEL_TIPRACK_ADAPTER':
return (
<>
{t(`timeline.error.${errorType}.body1`)}
<KnowledgeBaseLink to="airGap">
<Flex
justifyContent={JUSTIFY_SPACE_BETWEEN}
gridGap={SPACING.spacing8}
>
{t(`timeline.error.${errorType}.body`)}
<Btn
width="7.25rem"
textDecoration={TYPOGRAPHY.textDecorationUnderline}
css={BUTTON_LINK_STYLE}
onClick={() => {
dispatch(selectDesignerTab({ tab: 'startingDeck' }))
}}
>
{t(`timeline.error.${errorType}.link`)}
</KnowledgeBaseLink>
{t(`timeline.error.${errorType}.body2`)}
</>
</Btn>
</Flex>
)
default:
return bodyText
Expand Down
9 changes: 2 additions & 7 deletions protocol-designer/src/organisms/Alerts/TimelineAlerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import {
ALIGN_CENTER,
Banner,
DIRECTION_COLUMN,
Flex,
Expand Down Expand Up @@ -31,13 +30,9 @@ function TimelineAlertsComponent(): JSX.Element {
<Banner
type={alertType === 'error' ? 'error' : 'warning'}
key={`${alertType}:${key}`}
width="50%"
width="100%"
>
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing4}
alignItems={ALIGN_CENTER}
>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing4}>
<StyledText desktopStyle="bodyDefaultSemiBold">{data.title}</StyledText>
<StyledText desktopStyle="bodyDefaultRegular">
{data.description}
Expand Down
Loading

0 comments on commit 42699e3

Please sign in to comment.