Skip to content

Commit

Permalink
feat(app): Enable adding manual robot IP addresses in app settings (#…
Browse files Browse the repository at this point in the history
…3284)

Closes #2741
  • Loading branch information
Kadee80 authored and mcous committed Apr 3, 2019
1 parent 41c40c5 commit c34fcfa
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 49 deletions.
8 changes: 6 additions & 2 deletions app/src/components/AppSettings/AddManualIp/IpField.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@ export default function IpField (props: Props) {
form: {submitForm, dirty},
inputRef,
} = props

return (
<div className={styles.ip_field_group}>
<input
{...field}
onBlur={submitForm}
onBlur={event => {
field.onBlur(event)
if (field.value) submitForm()
}}
className={styles.ip_field}
type="text"
ref={inputRef}
/>
<IconButton
className={styles.ip_button}
className={styles.add_ip_button}
name="plus"
type="submit"
disabled={!dirty}
Expand Down
21 changes: 19 additions & 2 deletions app/src/components/AppSettings/AddManualIp/IpItem.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
// @flow
import * as React from 'react'
import {IconButton} from '@opentrons/components'
import {IconButton, Icon} from '@opentrons/components'
import styles from './styles.css'

import type {IconName} from '@opentrons/components'
type Props = {
candidate: string,
discovered: boolean,
removeIp: (ip: string) => mixed,
}
export default class IpItem extends React.Component<Props> {
remove = () => this.props.removeIp(this.props.candidate)
render () {
const iconName = this.props.discovered ? 'check' : 'ot-spinner'
return (
<div className={styles.ip_item_group}>
<div className={styles.ip_item}>{this.props.candidate}</div>
<DiscoveryIcon iconName={iconName} />
<IconButton
className={styles.ip_button}
className={styles.remove_ip_button}
name="minus"
onClick={this.remove}
/>
</div>
)
}
}

type DiscoveryIconProps = {
iconName: IconName,
}
function DiscoveryIcon (props: DiscoveryIconProps) {
const spin = props.iconName === 'ot-spinner'
return (
<div className={styles.discovery_icon}>
<Icon name={props.iconName} spin={spin} />
</div>
)
}
36 changes: 25 additions & 11 deletions app/src/components/AppSettings/AddManualIp/IpList.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
import * as React from 'react'
import {connect} from 'react-redux'
import {getConfig, removeManualIp} from '../../../config'
import {getLiveRobots} from '../../../discovery'

import type {State, Dispatch} from '../../../types'
import type {DiscoveryCandidates} from '../../../config'
import type {Robot, ReachableRobot} from '../../../discovery'

import IpItem from './IpItem'

type SP = {|
robots: Array<Robot | ReachableRobot>,
candidates: DiscoveryCandidates,
|}

Expand All @@ -19,30 +22,41 @@ type DP = {|
type Props = {...SP, ...DP}

function IpList (props: Props) {
const {candidates, removeManualIp} = props
const {candidates, removeManualIp, robots} = props
const candidateList = [].concat(candidates)

return (
<div>
{candidateList.map((c, index) => (
<IpItem candidate={c} key={index} removeIp={removeManualIp} />
))}
{candidateList.map((c, index) => {
const discovered = robots.some(r => r.ip === c)

return (
<IpItem
candidate={c}
key={index}
removeIp={removeManualIp}
discovered={discovered}
/>
)
})}
</div>
)
}

export default connect(
STP,
DTP
)(IpList)

function STP (state: State): SP {
function mapStateToProps (state: State): SP {
return {
robots: getLiveRobots(state),
candidates: getConfig(state).discovery.candidates,
}
}

function DTP (dispatch: Dispatch): DP {
function mapDispatchToProps (dispatch: Dispatch): DP {
return {
removeManualIp: ip => dispatch(removeManualIp(ip)),
}
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(IpList)
6 changes: 5 additions & 1 deletion app/src/components/AppSettings/AddManualIp/ManualIpForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import * as React from 'react'
import {connect} from 'react-redux'
import {getConfig, addManualIp} from '../../../config'
import {startDiscovery} from '../../../discovery'

import {Formik, Form, Field} from 'formik'
import IpField from './IpField'
Expand Down Expand Up @@ -62,6 +63,9 @@ function STP (state: State): SP {

function DTP (dispatch: Dispatch): DP {
return {
addManualIp: ip => dispatch(addManualIp(ip)),
addManualIp: ip => {
dispatch(addManualIp(ip))
dispatch(startDiscovery())
},
}
}
27 changes: 14 additions & 13 deletions app/src/components/AppSettings/AddManualIp/styles.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
@import '@opentrons/components';

:root {
--ip-group: {
display: flex;
justify-content: flex-start;
border: 1px solid var(--c-med-gray);
height: 2rem;

&:focus-within {
background-color: var(--c-white);
box-shadow: 0 0.125rem 0.25rem 0 color(var(--c-black) alpha(0.5));
}
}

--ip-item: {
flex: 1 0 100%;
padding: 0 1rem;
Expand Down Expand Up @@ -40,7 +28,7 @@
}
}

.ip_button {
.add_ip_button {
padding: 0.25rem;
flex: 0 0 2rem;
border-radius: 0;
Expand All @@ -66,4 +54,17 @@

.ip_item {
@apply --ip-item;

flex: 1 1 calc(100% - 4rem);
}

.remove_ip_button {
padding: 0.25rem;
flex: 0 0 2rem;
border-radius: 0;
}

.discovery_icon {
padding: 0.5rem;
flex: 0 0 2rem;
}
30 changes: 13 additions & 17 deletions app/src/components/AppSettings/AdvancedSettingsCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ type OP = {
type SP = {|
devToolsOn: boolean,
channel: UpdateChannel,
__ffShowManualIp: boolean,
|}

type DP = {|
Expand Down Expand Up @@ -74,21 +73,19 @@ function AdvancedSettingsCard (props: Props) {
logging.
</p>
</LabeledToggle>
{props.__ffShowManualIp && (
<LabeledButton
label="Manually Add Robot Network Addresses"
buttonProps={{
Component: Link,
children: 'manage',
to: `${props.match.url}/add-ip`,
}}
>
<p>
If your app is unable to automatically discover your robot, you
can manually add its IP address or hostname here
</p>
</LabeledButton>
)}
<LabeledButton
label="Manually Add Robot Network Addresses"
buttonProps={{
Component: Link,
children: 'manage',
to: `${props.match.url}/add-ip`,
}}
>
<p>
If your app is unable to automatically discover your robot, you can
manually add its IP address or hostname here
</p>
</LabeledButton>
</Card>
<Route
path={`${props.match.path}/add-ip`}
Expand All @@ -104,7 +101,6 @@ function mapStateToProps (state: State): SP {
return {
devToolsOn: config.devtools,
channel: config.update.channel,
__ffShowManualIp: Boolean(config.devInternal?.manualIp),
}
}

Expand Down
8 changes: 5 additions & 3 deletions app/src/components/ConnectPanel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import * as React from 'react'
import {connect} from 'react-redux'
import orderBy from 'lodash/orderBy'

import type {State, Dispatch} from '../../types'

import {
startDiscovery,
getScanning,
Expand All @@ -13,6 +11,8 @@ import {
getUnreachableRobots,
} from '../../discovery'

import type {State, Dispatch} from '../../types'

import {SidePanel} from '@opentrons/components'
import RobotList from './RobotList'
import RobotItem from './RobotItem'
Expand Down Expand Up @@ -48,7 +48,9 @@ function ConnectPanel (props: Props) {
<SidePanel title="Robots">
<ScanStatus {...props} />
<RobotList>
{props.robots.map(robot => <RobotItem key={robot.name} {...robot} />)}
{props.robots.map(robot => (
<RobotItem key={robot.name} {...robot} />
))}
{props.reachableRobots.map(robot => (
<RobotItem key={robot.name} {...robot} />
))}
Expand Down
7 changes: 7 additions & 0 deletions app/src/discovery/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type GetConnectableRobots = Selector<State, void, Array<Robot>>
type GetReachableRobots = Selector<State, void, Array<ReachableRobot>>
type GetUnreachableRobots = Selector<State, void, Array<UnreachableRobot>>
type GetAllRobots = Selector<State, void, Array<AnyRobot>>
type GetLiveRobots = Selector<State, void, Array<Robot | ReachableRobot>>
type GetConnectedRobot = Selector<State, void, ?Robot>

export const CONNECTABLE: ConnectableStatus = 'connectable'
Expand Down Expand Up @@ -128,6 +129,12 @@ export const getAllRobots: GetAllRobots = createSelector(
concat
)

export const getLiveRobots: GetLiveRobots = createSelector(
getConnectableRobots,
getReachableRobots,
concat
)

export const getConnectedRobot: GetConnectedRobot = createSelector(
getConnectableRobots,
robots => find(robots, 'connected')
Expand Down

0 comments on commit c34fcfa

Please sign in to comment.