Skip to content

Commit

Permalink
feat(app): Add and implement module selectors in calibration (#1895)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kadee80 authored Jul 18, 2018
1 parent 6aae77d commit 2cf1b4d
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 55 deletions.
20 changes: 20 additions & 0 deletions app/src/components/Page/RefreshWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow
import * as React from 'react'

type Props = {
refresh: () => mixed,
children: React.Node,
}
export default class RefreshWrapper extends React.Component<Props> {
render () {
const {children} = this.props
return (
<React.Fragment>
{children}
</React.Fragment>
)
}
componentDidMount () {
this.props.refresh()
}
}
3 changes: 2 additions & 1 deletion app/src/components/Page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react'
import styles from './styles.css'
import {TitleBar, type TitleBarProps} from '@opentrons/components'
import PageWrapper from './PageWrapper'
import RefreshWrapper from './RefreshWrapper'

type Props = {
titleBarProps?: TitleBarProps,
Expand All @@ -22,4 +23,4 @@ export default function Page (props: Props) {
)
}

export {PageWrapper}
export {PageWrapper, RefreshWrapper}
2 changes: 0 additions & 2 deletions app/src/components/UploadStatus/Status.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ function UploadResults (props: Props) {

let instructions

console.log(props)

if (uploadError) {
// instructions for an unsuccessful upload
instructions = (
Expand Down
18 changes: 2 additions & 16 deletions app/src/components/nav-bar/NavButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
selectors as robotSelectors,
constants as robotConstants
} from '../../robot'
import {getAnyRobotUpdateAvailable, fetchPipettes} from '../../http-api-client'
import {getAnyRobotUpdateAvailable} from '../../http-api-client'
import {getShellUpdate} from '../../shell'

import {NavButton} from '@opentrons/components'
Expand All @@ -26,9 +26,7 @@ type SP = Props & {
_robot: ?RobotService,
}

type DP = {dispatch: Dispatch}

export default withRouter(connect(mapStateToProps, null, mergeProps)(NavButton))
export default withRouter(connect(mapStateToProps)(NavButton))

function mapStateToProps (state: State, ownProps: OP): SP {
const {name} = ownProps
Expand Down Expand Up @@ -78,15 +76,3 @@ function mapStateToProps (state: State, ownProps: OP): SP {

return {...NAV_ITEM_BY_NAME[name], _robot}
}

function mergeProps (stateProps: SP, dispatchProps: DP, ownProps: OP): Props {
const {dispatch} = dispatchProps
const {_robot, url, disabled} = stateProps
let props: Props = {...ownProps, ...stateProps}

if (_robot && url === '/calibrate' && !disabled) {
props = {...props, onClick: () => dispatch(fetchPipettes(_robot))}
}

return props
}
83 changes: 60 additions & 23 deletions app/src/pages/Calibrate/Labware.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,59 @@
// setup instruments page
import * as React from 'react'
import {connect} from 'react-redux'
import {Route, Redirect, withRouter, type ContextRouter, type Match} from 'react-router'
import {Route, Redirect, withRouter, type Match} from 'react-router'
import {push} from 'react-router-redux'
import type {State} from '../../types'
import {
selectors as robotSelectors,
type Labware
} from '../../robot'
import {makeGetRobotSettings} from '../../http-api-client'
import Page from '../../components/Page'
import type {State, Dispatch} from '../../types'
import type {Labware, Robot, StateModule} from '../../robot'
import {selectors as robotSelectors} from '../../robot'
import {getModulesOn} from '../../config'
import type {Module} from '../../http-api-client'
import {makeGetRobotSettings, makeGetRobotModules, fetchModules} from '../../http-api-client'
import Page, {RefreshWrapper} from '../../components/Page'
import CalibrateLabware from '../../components/CalibrateLabware'
import SessionHeader from '../../components/SessionHeader'
import ReviewDeckModal from '../../components/ReviewDeckModal'
import ConfirmModal from '../../components/CalibrateLabware/ConfirmModal'

type OwnProps = {
type OP = {
match: Match
}

type StateProps = {
type SP = {
deckPopulated: boolean,
labware: ?Labware,
calibrateToBottom: boolean
calibrateToBottom: boolean,
robot: Robot,
modulesFlag: ?boolean,
modules: Array<StateModule>,
actualModules: ?Array<Module>,
}

type DispatchProps = {onBackClick: () => void}
type DP = {
dispatch: Dispatch
}

type Props = ContextRouter & StateProps & OwnProps & DispatchProps
type Props = SP & OP & {
onBackClick: () => void,
fetchModules: () => mixed,
}

export default withRouter(connect(makeMapStateToProps, mapDispatchToProps)(SetupDeckPage))
export default withRouter(connect(makeMapStateToProps, null, mergeProps)(SetupDeckPage))

function SetupDeckPage (props: Props) {
const {calibrateToBottom, labware, deckPopulated, onBackClick, match: {url, params: {slot}}} = props
const {
calibrateToBottom,
labware,
deckPopulated,
onBackClick,
fetchModules,
match: {url, params: {slot}}
} = props

return (
<React.Fragment>
<RefreshWrapper
refresh={fetchModules}
>
<Page
titleBarProps={{title: (<SessionHeader />)}}
>
Expand All @@ -56,36 +74,55 @@ function SetupDeckPage (props: Props) {
<ConfirmModal labware={labware} onBackClick={onBackClick} calibrateToBottom={calibrateToBottom}/>
)
}} />
</React.Fragment>
</RefreshWrapper>
)
}

function makeMapStateToProps (): (state: State, ownProps: OwnProps) => StateProps {
function makeMapStateToProps (): (state: State, ownProps: OP) => SP {
const getRobotSettings = makeGetRobotSettings()
const getRobotModules = makeGetRobotModules()

return (state, ownProps) => {
const {match: {url, params: {slot}}} = ownProps
const labware = robotSelectors.getLabware(state)
const currentLabware = labware.find((lw) => lw.slot === slot)
const name = robotSelectors.getConnectedRobotName(state)
const response = getRobotSettings(state, {name}).response
const settings = response && response.settings
const robot = robotSelectors.getConnectedRobot(state)

const settingsResponse = getRobotSettings(state, {name}).response
const settings = settingsResponse && settingsResponse.settings
const flag = !!settings && settings.find((s) => s.id === 'calibrateToBottom')
const calibrateToBottom = !!flag && flag.value

const modules = robotSelectors.getModules(state)
const modulesCall = getRobotModules(state, robot)
const modulesResponse = modulesCall.response
const actualModules = modulesResponse && modulesResponse.modules

return {
deckPopulated: !!robotSelectors.getDeckPopulated(state),
labware: currentLabware,
slot,
url,
calibrateToBottom
calibrateToBottom,
robot,
modulesFlag: getModulesOn(state),
modules,
actualModules
}
}
}

function mapDispatchToProps (dispatch, ownProps: OwnProps): DispatchProps {
function mergeProps (stateProps: SP, dispatchProps: DP, ownProps: OP): Props {
const {match: {url}} = ownProps
const {dispatch} = dispatchProps
const {robot} = stateProps
return {
onBackClick: () => { dispatch(push(url)) }
...stateProps,
...ownProps,
onBackClick: () => { dispatch(push(url)) },
fetchModules: () => {
dispatch(fetchModules(robot))
}
}
}
50 changes: 39 additions & 11 deletions app/src/pages/Calibrate/Pipettes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,45 @@
// setup pipettes component
import * as React from 'react'
import {connect} from 'react-redux'
import {Route, Redirect, type ContextRouter} from 'react-router'
import {Route, Redirect, type Match} from 'react-router'

import type {State} from '../../types'
import type {Pipette} from '../../robot'
import type {Pipette, Robot} from '../../robot'
import {selectors as robotSelectors} from '../../robot'
import {makeGetRobotPipettes} from '../../http-api-client'
import {makeGetRobotPipettes, fetchPipettes} from '../../http-api-client'

import Page from '../../components/Page'
import Page, {RefreshWrapper} from '../../components/Page'
import TipProbe from '../../components/TipProbe'
import ConfirmTipProbeModal from '../../components/ConfirmTipProbeModal'
import {PipetteTabs, Pipettes} from '../../components/calibrate-pipettes'

import SessionHeader from '../../components/SessionHeader'

type StateProps = {
type SP = {
pipettes: Array<Pipette>,
currentPipette: ?Pipette
currentPipette: ?Pipette,
robot: Robot,
}

type OwnProps = ContextRouter
type DP = {dispatch: Dispatch}

type Props = StateProps & OwnProps
type OP = {
match: Match
}

type Props = SP & OP & {
fetchPipettes: () => mixed
}

export default connect(makeMapStateToProps)(CalibratePipettesPage)
export default connect(makeMapStateToProps, null, mergeProps)(CalibratePipettesPage)

function CalibratePipettesPage (props: Props) {
const {pipettes, currentPipette, match: {url, params}} = props
const {
pipettes,
currentPipette,
fetchPipettes,
match: {url, params}
} = props
const confirmTipProbeUrl = `${url}/confirm-tip-probe`

// redirect back to mountless route if mount doesn't exist
Expand All @@ -37,6 +49,9 @@ function CalibratePipettesPage (props: Props) {
}

return (
<RefreshWrapper
refresh={fetchPipettes}
>
<Page
titleBarProps={{title: (<SessionHeader />)}}
>
Expand All @@ -57,22 +72,35 @@ function CalibratePipettesPage (props: Props) {
)} />
)}
</Page>
</RefreshWrapper>
)
}

function makeMapStateToProps (): (State, OwnProps) => StateProps {
function makeMapStateToProps (): (State, OP) => SP {
const getCurrentPipette = robotSelectors.makeGetCurrentPipette()
const getAttachedPipettes = makeGetRobotPipettes()

return (state, props) => {
const name = robotSelectors.getConnectedRobotName(state)
const robot = robotSelectors.getConnectedRobot(state)
const pipettesResponse = getAttachedPipettes(state, {name})

return {
name,
robot,
pipettes: robotSelectors.getPipettes(state),
currentPipette: getCurrentPipette(state, props),
actualPipettes: pipettesResponse.response
}
}
}

function mergeProps (stateProps: SP, dispatchProps: DP, ownProps: OP): Props {
const {dispatch} = dispatchProps
const {robot} = stateProps
return {
...stateProps,
...ownProps,
fetchPipettes: () => { dispatch(fetchPipettes(robot)) }
}
}
8 changes: 8 additions & 0 deletions app/src/robot/api-client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ export default function client (dispatch) {

if (apiSession.modules) {
update.modulesBySlot = {}
// TODO (ka 2018-7-17): MOCKED MODULES by slot here instead of session.py uncomment below to test
// update.modulesBySlot = {
// '1': {
// id: '4374062089',
// name: 'magdeck',
// slot: '1'
// }
// }
apiSession.modules.forEach(addApiModuleToModules)
}

Expand Down
19 changes: 18 additions & 1 deletion app/src/robot/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import type {
LabwareCalibrationStatus,
LabwareType,
Robot,
SessionStatus
SessionStatus,
StateModule
} from './types'

import {
Expand Down Expand Up @@ -313,6 +314,22 @@ export const getPipettesCalibrated = createSelector(
)
)

export function getModulesBySlot (state: State) {
return session(state).modulesBySlot
}

export const getModules = createSelector(
getModulesBySlot,
(modules): ?StateModule[] => {
return Object.keys(modules)
.filter(isSlot)
.map((slot) => {
const module = modules[slot]
return {...module}
})
}
)

export function getLabwareBySlot (state: State) {
return session(state).labwareBySlot
}
Expand Down
Loading

0 comments on commit 2cf1b4d

Please sign in to comment.