Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): Add and implement module selectors in calibration #1895

Merged
merged 2 commits into from
Jul 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

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