diff --git a/components/interfaces/DeckSlot.js b/components/interfaces/DeckSlot.js
index 3dd65712007..93a96e8c09d 100644
--- a/components/interfaces/DeckSlot.js
+++ b/components/interfaces/DeckSlot.js
@@ -3,8 +3,6 @@ import * as React from 'react'
export type DeckSlotProps = {
slot: string,
- width: number,
- height: number,
highlighted?: boolean,
containerType?: string,
children?: React.Node
diff --git a/components/src/deck/LabwareContainer.js b/components/src/deck/LabwareContainer.js
index 0837aac50f1..79373441598 100644
--- a/components/src/deck/LabwareContainer.js
+++ b/components/src/deck/LabwareContainer.js
@@ -1,5 +1,6 @@
// @flow
import * as React from 'react'
+import {SLOT_HEIGHT_MM, SLOT_WIDTH_MM} from '@opentrons/shared-data'
import styles from './LabwareContainer.css'
const defs = {roundSlotClipPath: 'roundSlotClipPath'} // TODO: import these defs instead of hard-coding in applications? Or should they be passed to children?
@@ -7,14 +8,16 @@ const defs = {roundSlotClipPath: 'roundSlotClipPath'} // TODO: import these defs
type Props = {
x?: number,
y?: number,
- height: number,
- width: number,
+ height?: number,
+ width?: number,
highlighted?: boolean,
children?: React.Node,
}
export default function LabwareContainer (props: Props) {
- const {x, y, height, width, highlighted, children} = props
+ const {x, y, highlighted, children} = props
+ const height = props.height || SLOT_HEIGHT_MM
+ const width = props.width || SLOT_WIDTH_MM
return (
diff --git a/protocol-designer/src/components/LabwareSelectionModal/index.js b/protocol-designer/src/components/LabwareSelectionModal/index.js
index f1d0f42cc4c..f1b42dfd7e8 100644
--- a/protocol-designer/src/components/LabwareSelectionModal/index.js
+++ b/protocol-designer/src/components/LabwareSelectionModal/index.js
@@ -17,7 +17,7 @@ type SP = {
function mapStateToProps (state: BaseState): SP {
return {
- slot: labwareIngredSelectors.canAdd(state) || null,
+ slot: labwareIngredSelectors.selectedAddLabwareSlot(state) || null,
permittedTipracks: pipetteSelectors.permittedTipracks(state),
}
}
diff --git a/protocol-designer/src/components/labware/ClickableText.js b/protocol-designer/src/components/labware/ClickableText.js
index 42c68c9d285..5affbb28bc4 100644
--- a/protocol-designer/src/components/labware/ClickableText.js
+++ b/protocol-designer/src/components/labware/ClickableText.js
@@ -8,7 +8,7 @@ type Props = {
height?: string | number,
text?: string,
iconName?: IconName,
- onClick?: (e: SyntheticEvent<*>) => void,
+ onClick?: (e: SyntheticEvent<*>) => mixed,
}
const DEFAULT_HEIGHT = 15
diff --git a/protocol-designer/src/components/labware/DisabledSelectSlotOverlay.js b/protocol-designer/src/components/labware/DisabledSelectSlotOverlay.js
index b5f2dacd269..41549cf2da5 100644
--- a/protocol-designer/src/components/labware/DisabledSelectSlotOverlay.js
+++ b/protocol-designer/src/components/labware/DisabledSelectSlotOverlay.js
@@ -1,26 +1,25 @@
// @flow
import React from 'react'
import cx from 'classnames'
-import {HandleKeypress, type DeckSlot} from '@opentrons/components'
+import {HandleKeypress} from '@opentrons/components'
import styles from './labware.css'
-type DisabledSelectSlotOverlayProps = {setMoveLabwareMode: (slot: ?DeckSlot) => void}
-class DisabledSelectSlotOverlay extends React.Component {
- cancelMove = () => {
- this.props.setMoveLabwareMode()
- }
- render () {
- return (
-
-
-
-
- Select a slot
-
+type Props = {
+ cancelMove: () => mixed,
+}
+
+function DisabledSelectSlotOverlay (props: Props) {
+ const {cancelMove} = props
+ return (
+
+
+
+
+ Select a slot
-
- )
- }
+
+
+ )
}
export default DisabledSelectSlotOverlay
diff --git a/protocol-designer/src/components/labware/LabwareOnDeck.js b/protocol-designer/src/components/labware/LabwareOnDeck.js
index 6d925e6614c..34b9032ed27 100644
--- a/protocol-designer/src/components/labware/LabwareOnDeck.js
+++ b/protocol-designer/src/components/labware/LabwareOnDeck.js
@@ -1,13 +1,4 @@
// @flow
-
-// On an empty slot:
-// * Renders a slot on the deck
-// * Renders Add Labware mouseover button
-//
-// On a slot with a container:
-// * Renders a SelectablePlate in the slot
-// * Renders Add Ingreds / Delete container mouseover buttons, and dispatches their actions
-
import React from 'react'
import cx from 'classnames'
import {
@@ -20,7 +11,6 @@ import {
clickOutside,
type DeckSlot,
} from '@opentrons/components'
-import {getLabware} from '@opentrons/shared-data'
import styles from './labware.css'
import ClickableText from './ClickableText'
@@ -30,32 +20,25 @@ import DisabledSelectSlotOverlay from './DisabledSelectSlotOverlay.js'
const EnhancedNameThisLabwareOverlay = clickOutside(NameThisLabwareOverlay)
-function OccupiedDeckSlotOverlay ({
+function LabwareDeckSlotOverlay ({
canAddIngreds,
- containerId,
- slot,
- containerType,
- containerName,
- openIngredientSelector,
- setMoveLabwareMode,
- deleteContainer,
+ deleteLabware,
+ editLiquids,
+ moveLabwareSource,
}) {
return (
{canAddIngreds &&
openIngredientSelector(containerId)}
+ onClick={editLiquids}
iconName='pencil' y='15%' text='Name & Liquids' />
}
setMoveLabwareMode(slot)}
+ onClick={moveLabwareSource}
iconName='cursor-move' y='40%' text='Move' />
(
- window.confirm(`Are you sure you want to permanently delete ${containerName || containerType} in slot ${slot}?`) &&
- deleteContainer({containerId, slot, containerType})
- )}
+ onClick={deleteLabware}
iconName='close' y='65%' text='Delete' />
)
@@ -67,13 +50,13 @@ const labwareImages = {
'trash-box': IMG_TRASH,
}
-type SlotWithContainerProps = {
+type SlotWithLabwareProps = {
containerType: string,
displayName: string,
containerId: string,
}
-function SlotWithContainer (props: SlotWithContainerProps) {
+function SlotWithLabware (props: SlotWithLabwareProps) {
const {containerType, displayName, containerId} = props
return (
@@ -90,152 +73,143 @@ function SlotWithContainer (props: SlotWithContainerProps) {
)
}
+type EmptyDestinationSlotOverlayProps = {
+ moveLabwareDestination: (e?: SyntheticEvent<*>) => mixed,
+}
+function EmptyDestinationSlotOverlay (props: EmptyDestinationSlotOverlayProps) {
+ const {moveLabwareDestination} = props
+
+ const handleSelectMoveDestination = (e: SyntheticEvent<*>) => {
+ e.preventDefault()
+ moveLabwareDestination()
+ }
+
+ return (
+
+
+
+
+ )
+}
+
+type EmptyDeckSlotOverlayProps = {
+ addLabware: (e: SyntheticEvent<*>) => mixed,
+}
+function EmptyDeckSlotOverlay (props: EmptyDeckSlotOverlayProps) {
+ const {addLabware} = props
+ return (
+
+
+
+ window.alert('NOT YET IMPLEMENTED: Add Copy') /* TODO: New Copy feature */}
+ iconName='content-copy' y='55%' text='Add Copy' />
+
+ )
+}
+
type LabwareOnDeckProps = {
slot: DeckSlot,
-
containerId: string,
- containerType: string,
containerName: ?string,
- showNameOverlay: ?boolean,
-
- // canAdd: boolean,
+ containerType: string,
- activeModals: {
- ingredientSelection: ?{
- containerName: ?string,
- slot: ?DeckSlot,
- },
- labwareSelection: boolean,
- },
- openIngredientSelector: (containerId: string) => void,
+ showNameOverlay: ?boolean,
+ slotHasLabware: boolean,
+ highlighted: boolean,
- // createContainer: ({slot: string, containerType: string}) => mixed,
- deleteContainer: ({containerId: string, slot: DeckSlot, containerType: string}) => void,
- modifyContainer: ({containerId: string, modify: {[field: string]: mixed}}) => void, // eg modify = {name: 'newName'}
+ addLabwareMode: boolean,
+ canAddIngreds: boolean,
+ deckSetupMode: boolean,
+ moveLabwareMode: boolean,
- openLabwareSelector: ({slot: DeckSlot}) => void,
- // closeLabwareSelector: ({slot: string}) => mixed,
+ addLabware: () => mixed,
+ editLiquids: () => mixed,
+ deleteLabware: () => mixed,
- setMoveLabwareMode: (slot: ?DeckSlot) => void,
+ cancelMove: () => mixed,
+ moveLabwareDestination: () => mixed,
+ moveLabwareSource: () => mixed,
slotToMoveFrom: ?DeckSlot,
- moveLabware: (slot: DeckSlot) => void,
-
- height?: number,
- width?: number,
- highlighted: boolean,
- deckSetupMode: boolean,
+ setLabwareName: (name: ?string) => mixed,
+ setDefaultLabwareName: () => mixed,
}
-
export default function LabwareOnDeck (props: LabwareOnDeckProps) {
const {
slot,
-
containerId,
- containerType,
containerName,
- showNameOverlay,
-
- // canAdd,
+ containerType,
- activeModals,
- openIngredientSelector,
+ showNameOverlay,
+ slotHasLabware,
+ highlighted,
- // createContainer,
- deleteContainer,
- modifyContainer,
+ addLabwareMode,
+ canAddIngreds,
+ deckSetupMode,
+ moveLabwareMode,
- openLabwareSelector,
- // closeLabwareSelector,
+ addLabware,
+ editLiquids,
+ deleteLabware,
- setMoveLabwareMode,
+ cancelMove,
+ moveLabwareDestination,
+ moveLabwareSource,
slotToMoveFrom,
- moveLabware,
- height,
- width,
- highlighted,
-
- deckSetupMode,
+ setDefaultLabwareName,
+ setLabwareName,
} = props
- const slotIsOccupied = !!containerType
-
- let canAddIngreds: boolean = !showNameOverlay
-
- // labware definition's metadata.isValueSource defaults to true,
- // only use it when it's defined as false
- const labwareInfo = getLabware(containerType)
- if (!labwareInfo || labwareInfo.metadata.isValidSource === false) {
- canAddIngreds = false
+ // determine what overlay to show
+ let overlay = null
+ if (deckSetupMode && !addLabwareMode) {
+ if (moveLabwareMode) {
+ overlay = (slotToMoveFrom === slot)
+ ?
+ :
+ } else if (showNameOverlay) {
+ overlay =
+ } else {
+ overlay = (slotHasLabware)
+ ?
+ :
+ }
}
- const setDefaultLabwareName = () => modifyContainer({
- containerId,
- modify: {name: null},
- })
-
- const handleSelectMoveDestination = (e: SyntheticEvent<*>) => {
- e.preventDefault()
- moveLabware(slot)
- }
- const cancelMove = () => {
- setMoveLabwareMode()
- }
+ const labwareOrSlot = (slotHasLabware)
+ ?
+ :
return (
-
- {/* The actual deck slot container: rendering of container, or rendering of empty slot */}
- {slotIsOccupied
- ?
- :
- }
-
- {(!deckSetupMode || activeModals.labwareSelection)
- // "Add Labware" labware selection dropdown menu
- ? null
- : (slotToMoveFrom
- // Mouseover empty slot -- Add (or Copy if in copy mode)
- ?
- moveLabware(slot)} />
-
-
- :
-
- openLabwareSelector({slot})}
- iconName='plus' y='30%' text='Add Labware' />
- window.alert('NOT YET IMPLEMENTED: Add Copy') /* TODO: New Copy feature */}
- iconName='content-copy' y='55%' text='Add Copy' />
-
- )
- }
-
- {slotToMoveFrom === slot &&
- }
-
- {deckSetupMode && slotIsOccupied && !slotToMoveFrom && !showNameOverlay &&
-
- }
-
- {deckSetupMode && showNameOverlay &&
-
- }
+
+ {labwareOrSlot}
+ {overlay}
)
}
diff --git a/protocol-designer/src/components/labware/NameThisLabwareOverlay.js b/protocol-designer/src/components/labware/NameThisLabwareOverlay.js
index 74622ed8b2a..443eeb1b73c 100644
--- a/protocol-designer/src/components/labware/NameThisLabwareOverlay.js
+++ b/protocol-designer/src/components/labware/NameThisLabwareOverlay.js
@@ -3,15 +3,12 @@ import * as React from 'react'
import ForeignDiv from '../../components/ForeignDiv.js'
import ClickableText from './ClickableText'
import styles from './labware.css'
-import type {ClickOutsideInterface, DeckSlot} from '@opentrons/components'
+import type {ClickOutsideInterface} from '@opentrons/components'
type Props = {
- containerType: string,
- containerId: string,
- slot: DeckSlot,
+ setLabwareName: (name: ?string) => mixed,
// TODO Ian 2018-02-16 type these fns elsewhere and import the type
- modifyContainer: (args: {containerId: string, modify: {[field: string]: mixed}}) => void,
- deleteContainer: (args: {containerId: string, slot: DeckSlot, containerType: string}) => void,
+ deleteLabware: () => mixed,
} & ClickOutsideInterface
type State = {
@@ -44,21 +41,13 @@ export default class NameThisLabwareOverlay extends React.Component {
- const { containerId, modifyContainer } = this.props
const containerName = this.state.inputValue || null
-
- modifyContainer({
- containerId,
- modify: { name: containerName },
- })
+ this.props.setLabwareName(containerName)
}
render () {
const {
- containerType,
- containerId,
- slot,
- deleteContainer,
+ deleteLabware,
passRef,
} = this.props
@@ -79,7 +68,7 @@ export default class NameThisLabwareOverlay extends React.Component
- deleteContainer({containerId, slot, containerType})}
+
diff --git a/protocol-designer/src/containers/LabwareContainer.js b/protocol-designer/src/containers/LabwareContainer.js
index 77725c97691..81557379dea 100644
--- a/protocol-designer/src/containers/LabwareContainer.js
+++ b/protocol-designer/src/containers/LabwareContainer.js
@@ -2,17 +2,15 @@
import * as React from 'react'
import {connect} from 'react-redux'
-import {getLabware} from '@opentrons/shared-data'
+import {getLabware, getIsTiprack} from '@opentrons/shared-data'
import {selectors} from '../labware-ingred/reducers'
import {
openIngredientSelector,
- createContainer,
deleteContainer,
modifyContainer,
- openLabwareSelector,
- closeLabwareSelector,
+ openAddLabwareModal,
setMoveLabwareMode,
moveLabware,
@@ -23,74 +21,120 @@ import {LabwareOnDeck} from '../components/labware'
import type {BaseState} from '../types'
import type {DeckSlot} from '@opentrons/components'
-type OwnProps = {
+type OP = {
slot: DeckSlot,
}
type Props = React.ElementProps
-type DispatchProps = {
- createContainer: mixed,
- deleteContainer: mixed,
- modifyContainer: mixed,
+type DP = {
+ addLabware: () => mixed,
+ editLiquids: () => mixed,
+ deleteLabware: () => mixed,
- openIngredientSelector: mixed,
- openLabwareSelector: mixed,
+ cancelMove: () => mixed,
+ moveLabwareDestination: () => mixed,
+ moveLabwareSource: () => mixed,
- closeLabwareSelector: mixed,
-
- setMoveLabwareMode: mixed,
- moveLabware: mixed,
+ setLabwareName: (name: ?string) => mixed,
+ setDefaultLabwareName: () => mixed,
}
-type StateProps = $Diff
+type SP = $Diff
-function mapStateToProps (state: BaseState, ownProps: OwnProps): StateProps {
+function mapStateToProps (state: BaseState, ownProps: OP): SP {
const {slot} = ownProps
const container = selectors.containersBySlot(state)[ownProps.slot]
const labwareNames = selectors.getLabwareNames(state)
- const containerInfo = (container)
- ? {containerType: container.type, containerId: container.id, containerName: labwareNames[container.id]}
- : {}
+
+ const containerType = container && container.type
+ const containerId = container && container.id
+ const containerName = containerId && labwareNames[containerId]
const selectedContainer = selectors.getSelectedContainer(state)
const isSelectedSlot = !!(selectedContainer && selectedContainer.slot === slot)
const deckSetupMode = steplistSelectors.getSelectedTerminalItemId(state) === START_TERMINAL_ITEM_ID
- const labwareHasName = container && selectors.getSavedLabware(state)[container.id]
- const labwareData = container && getLabware(container.type)
- // TODO: Ian 2018-07-10 use shared-data accessor
- const isTiprack = labwareData && labwareData.metadata.isTiprack
+ const labwareHasName = container && selectors.getSavedLabware(state)[containerId]
+ const isTiprack = getIsTiprack(containerType)
+ const showNameOverlay = container && !isTiprack && !labwareHasName
+
+ const slotToMoveFrom = selectors.slotToMoveFrom(state)
+ const activeModals = selectors.activeModals(state)
+
+ const slotHasLabware = !!containerType
+ const addLabwareMode = activeModals.labwareSelection
+ const moveLabwareMode = Boolean(slotToMoveFrom)
+
+ const setDefaultLabwareName = () => modifyContainer({
+ containerId,
+ modify: {name: null},
+ })
+
+ // labware definition's metadata.isValidSource defaults to true,
+ // only use it when it is defined as false
+ let canAddIngreds: boolean = !showNameOverlay
+ const labwareInfo = getLabware(containerType)
+ if (!labwareInfo || labwareInfo.metadata.isValidSource === false) {
+ canAddIngreds = false
+ }
return {
- ...containerInfo,
- slot,
- showNameOverlay: container && !isTiprack && !labwareHasName,
- canAdd: selectors.canAdd(state),
- activeModals: selectors.activeModals(state),
- slotToMoveFrom: selectors.slotToMoveFrom(state),
+ slotHasLabware,
+ addLabwareMode,
+ moveLabwareMode,
+ setDefaultLabwareName,
+ canAddIngreds,
+ labwareInfo,
+
+ showNameOverlay,
+ slotToMoveFrom,
highlighted: (deckSetupMode)
- // in deckSetupMode, labware is highlighted when selected (currently editing ingredients)
- // or when targeted by an open "Add Labware" modal
- ? (isSelectedSlot || selectors.canAdd(state) === slot)
- // outside of deckSetupMode, labware is highlighted when step/substep is hovered
- : steplistSelectors.hoveredStepLabware(state).includes(container && container.id),
+ // in deckSetupMode, labware is highlighted when selected (currently editing ingredients)
+ // or when targeted by an open "Add Labware" modal
+ ? (isSelectedSlot || selectors.selectedAddLabwareSlot(state) === slot)
+ // outside of deckSetupMode, labware is highlighted when step/substep is hovered
+ : steplistSelectors.hoveredStepLabware(state).includes(containerId),
deckSetupMode,
+
+ slot,
+ containerName,
+ containerType,
+ containerId,
}
}
-const mapDispatchToProps = {
- createContainer,
- deleteContainer,
- modifyContainer,
-
- openIngredientSelector,
- openLabwareSelector,
-
- closeLabwareSelector,
+function mergeProps (stateProps: SP, dispatchProps: {dispatch: Dispatch<*>}, ownProps: OP): Props {
+ const {slot} = ownProps
+ const {dispatch} = dispatchProps
+ const {containerId, containerName, containerType} = stateProps
+
+ const actions = {
+ addLabware: () => dispatch(openAddLabwareModal({slot})),
+ editLiquids: () => dispatch(openIngredientSelector(containerId)),
+ deleteLabware: () => (
+ window.confirm(`Are you sure you want to permanently delete ${containerName || containerType} in slot ${slot}?`) &&
+ dispatch(deleteContainer({containerId, slot, containerType}))
+ ),
+
+ cancelMove: () => dispatch(setMoveLabwareMode()),
+ moveLabwareDestination: () => dispatch(moveLabware(slot)),
+ moveLabwareSource: () => dispatch(setMoveLabwareMode(slot)),
+
+ setLabwareName: (name: ?string) => dispatch(modifyContainer({
+ containerId,
+ modify: {name},
+ })),
+ setDefaultLabwareName: () => dispatch(modifyContainer({
+ containerId,
+ modify: {name: null},
+ })),
+ }
- setMoveLabwareMode,
- moveLabware,
+ return {
+ ...stateProps,
+ ...actions,
+ }
}
-export default connect(mapStateToProps, mapDispatchToProps)(LabwareOnDeck)
+export default connect(mapStateToProps, null, mergeProps)(LabwareOnDeck)
diff --git a/protocol-designer/src/labware-ingred/actions.js b/protocol-designer/src/labware-ingred/actions.js
index 347e8a14918..98e21e8aca7 100644
--- a/protocol-designer/src/labware-ingred/actions.js
+++ b/protocol-designer/src/labware-ingred/actions.js
@@ -12,8 +12,8 @@ import type {DeckSlot} from '@opentrons/components'
// ===== Labware selector actions =====
-export const openLabwareSelector = createAction(
- 'OPEN_LABWARE_SELECTOR',
+export const openAddLabwareModal = createAction(
+ 'OPEN_ADD_LABWARE_MODAL',
(args: {slot: DeckSlot}) => args
)
diff --git a/protocol-designer/src/labware-ingred/reducers/index.js b/protocol-designer/src/labware-ingred/reducers/index.js
index a375828f845..cdc774cbff8 100644
--- a/protocol-designer/src/labware-ingred/reducers/index.js
+++ b/protocol-designer/src/labware-ingred/reducers/index.js
@@ -48,7 +48,7 @@ const nextEmptySlot = loadedContainersSubstate => {
// modeLabwareSelection: boolean. If true, we're selecting labware to add to a slot
// (this state just toggles a modal)
const modeLabwareSelection = handleActions({
- OPEN_LABWARE_SELECTOR: (state, action: ActionType) =>
+ OPEN_ADD_LABWARE_MODAL: (state, action: ActionType) =>
action.payload.slot,
CLOSE_LABWARE_SELECTOR: () => false,
CREATE_CONTAINER: () => false,
@@ -363,7 +363,8 @@ const disposalLabwareOptions: Selector = createSelector(
}, [])
)
-const canAdd = (state: BaseState) => rootSelector(state).modeLabwareSelection // false or selected slot to add labware to, eg 'A2'
+// false or selected slot to add labware to, eg 'A2'
+const selectedAddLabwareSlot = (state: BaseState) => rootSelector(state).modeLabwareSelection
const getSavedLabware = (state: BaseState) => rootSelector(state).savedLabware
@@ -470,7 +471,7 @@ export const selectors = {
allIngredientNamesIds,
loadedContainersBySlot,
containersBySlot,
- canAdd,
+ selectedAddLabwareSlot,
disposalLabwareOptions,
labwareOptions,
hasLiquid,