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

refactor(app): Add connnect to unsecured on select to ConnectionCard #2504

Merged
merged 4 commits into from
Oct 17, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
39 changes: 11 additions & 28 deletions app/src/components/RobotSettings/ConnectionCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,19 @@ import {getIn} from '@thi.ng/paths'
import find from 'lodash/find'

import {getConfig} from '../../config'
import {
makeGetRobotNetworkingStatus,
makeGetRobotWifiList,
} from '../../http-api-client'
import {RefreshCard} from '@opentrons/components'
import {
ConnectionStatusMessage,
ConnectionInfo,
AvailableNetworks,
} from './connection'
import {makeGetRobotNetworkingStatus} from '../../http-api-client'
import {Card} from '@opentrons/components'
import SelectNetwork from './SelectNetwork'
import {ConnectionStatusMessage, ConnectionInfo} from './connection'

import type {State} from '../../types'
import type {ViewableRobot} from '../../discovery'
import type {
WifiNetworkList,
InternetStatus,
NetworkInterface,
} from '../../http-api-client'
import type {InternetStatus, NetworkInterface} from '../../http-api-client'

type OP = {robot: ViewableRobot}

type SP = {|
__featureEnabled: boolean,
wifiList: ?WifiNetworkList,
internetStatus: ?InternetStatus,
wifiNetwork: ?NetworkInterface,
ethernetNetwork: ?NetworkInterface,
Expand All @@ -39,46 +28,40 @@ type Props = {...$Exact<OP>, ...SP}

const __FEATURE_FLAG = 'devInternal.manageRobotConnection.newCard'

export default connect(
makeMapStateToProps
/* mapDispatchToProps */
)(ConnectionCard)
export default connect(makeSTP)(ConnectionCard)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
export default connect(makeSTP)(ConnectionCard)
export default connect(mapSTP)(ConnectionCard)


const TITLE = 'Connectivity'
function ConnectionCard (props: Props) {
// TODO(mc, 2018-10-15): remove feature flag
if (!props.__featureEnabled) return null

const {robot, wifiList, internetStatus, wifiNetwork, ethernetNetwork} = props
const {robot, internetStatus, wifiNetwork, ethernetNetwork} = props

return (
<RefreshCard title={TITLE} refresh={() => console.log('placeholder')}>
<Card title={TITLE}>
<ConnectionStatusMessage
type={robot.local ? 'USB' : 'Wi-Fi'}
status={internetStatus}
/>
<ConnectionInfo connection={wifiNetwork} title="Wi-Fi">
<AvailableNetworks list={wifiList} />
<SelectNetwork key={robot.name} robot={robot} />
</ConnectionInfo>
<ConnectionInfo connection={ethernetNetwork} title="USB" wired />
</RefreshCard>
</Card>
)
}

function makeMapStateToProps (): (State, OP) => SP {
function makeSTP (): (State, OP) => SP {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
function makeSTP (): (State, OP) => SP {
function mapSTP (): (State, OP) => SP {

const getNetworkingStatusCall = makeGetRobotNetworkingStatus()
const getWifiListCall = makeGetRobotWifiList()

return (state, ownProps) => {
const {robot} = ownProps
const {response: statusResponse} = getNetworkingStatusCall(state, robot)
const {response: listResponse} = getWifiListCall(state, robot)
const internetStatus = statusResponse && statusResponse.status
const interfaces = statusResponse && statusResponse.interfaces

return {
internetStatus,
wifiList: listResponse && listResponse.list,
wifiNetwork: find(interfaces, {type: 'wifi'}),
ethernetNetwork: find(interfaces, {type: 'ethernet'}),
__featureEnabled: !!getIn(getConfig(state), __FEATURE_FLAG),
Expand Down
122 changes: 122 additions & 0 deletions app/src/components/RobotSettings/SelectNetwork.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// @flow
import * as React from 'react'
import {connect} from 'react-redux'
import find from 'lodash/find'

import {
NO_SECURITY,
fetchWifiList,
configureWifi,
makeGetRobotWifiList,
makeGetRobotWifiConfigure,
} from '../../http-api-client'
import {NetworkDropdown} from './connection'
import {Portal} from '../portal'
import {IntervalWrapper, SpinnerModal} from '@opentrons/components'

import type {State, Dispatch} from '../../types'
import type {ViewableRobot} from '../../discovery'
import type {WifiNetwork, WifiNetworkList} from '../../http-api-client'

type OP = {robot: ViewableRobot}

type SP = {|list: ?WifiNetworkList, connectingTo: ?string|}

type DP = {|
getList: () => mixed,
configure: (network: WifiNetwork) => mixed,
|}

type Props = {...$Exact<OP>, ...SP, ...DP}

type SelectNetworkState = {value: ?string}

const LIST_REFRESH_MS = 15000

class SelectNetwork extends React.Component<Props, SelectNetworkState> {
constructor (props) {
super(props)
// prepopulate selected SSID with currently connected network, if any
this.state = {value: this.getActiveSsid()}
}

onChange = (network: WifiNetwork) => {
this.setState({value: network.ssid})
this.props.configure(network)
}

getActiveSsid (): ?string {
const activeNetwork = find(this.props.list, 'active')
return activeNetwork && activeNetwork.ssid
}

componentDidUpdate (prevProps) {
// if we don't have a selected network in component state and the list has
// updated, seed component state with active ssid from props
if (!this.state.value && this.props.list !== prevProps.list) {
this.setState({value: this.getActiveSsid()})
}
}

render () {
const {list, connectingTo, getList} = this.props
const {value} = this.state

return (
<IntervalWrapper refresh={getList} interval={LIST_REFRESH_MS}>
<NetworkDropdown
list={list}
value={value}
disabled={connectingTo != null}
onChange={this.onChange}
/>
{connectingTo && (
<Portal>
<SpinnerModal
message={`Attempting to connect to network ${connectingTo}`}
/>
</Portal>
)}
</IntervalWrapper>
)
}
}

function makeSTP (): (State, OP) => SP {
const getWifiListCall = makeGetRobotWifiList()
const getWifiConfigureCall = makeGetRobotWifiConfigure()

return (state, ownProps) => {
const {robot} = ownProps
const {response: listResponse} = getWifiListCall(state, robot)
const {
request: cfgRequest,
inProgress: cfgInProgress,
error: cfgError,
} = getWifiConfigureCall(state, robot)

return {
list: listResponse && listResponse.list,
connectingTo:
!cfgError && cfgInProgress && cfgRequest ? cfgRequest.ssid : null,
}
}
}

function DTP (dispatch: Dispatch, ownProps: OP): DP {
const {robot} = ownProps

return {
getList: () => dispatch(fetchWifiList(robot)),
configure: network => {
if (network.securityType === NO_SECURITY) {
return dispatch(configureWifi(robot, {ssid: network.ssid}))
}
},
}
}

export default connect(
makeSTP,
DTP
)(SelectNetwork)
28 changes: 22 additions & 6 deletions app/src/components/RobotSettings/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// UI components for displaying connection info
import * as React from 'react'
import Select from 'react-select'
import find from 'lodash/find'
import {Icon} from '@opentrons/components'
import {CardContentHalf} from '../layout'
import styles from './styles.css'
Expand Down Expand Up @@ -68,22 +69,37 @@ export function ConnectionInfo (props: ConnectionInfoProps) {
)
}

type AvailableNetworksProps = {list: ?WifiNetworkList}
type SelectNetworkOption = {
...$Exact<WifiNetwork>,
value: string,
label: React.Node,
}

type NetworkDropdownProps = {
list: ?WifiNetworkList,
value: ?string,
disabled: boolean,
onChange: SelectNetworkOption => mixed,
}

export function AvailableNetworks (props: AvailableNetworksProps) {
export function NetworkDropdown (props: NetworkDropdownProps) {
const {value, disabled, onChange} = props
const list = props.list || []
const options = list.map(NetworkOption)
const selectedOption = find(options, {value})

return (
<Select
value={options[0]}
className={styles.wifi_dropdown}
onChange={e => console.log(e)}
isDisabled={disabled}
value={selectedOption}
onChange={onChange}
options={options}
/>
)
}

function NetworkOption (nw: WifiNetwork): {value: string, label: React.Node} {
function NetworkOption (nw: WifiNetwork): SelectNetworkOption {
const value = nw.ssid
const connectedIcon = nw.active ? (
<Icon name="check" className={styles.wifi_option_icon} />
Expand Down Expand Up @@ -121,7 +137,7 @@ function NetworkOption (nw: WifiNetwork): {value: string, label: React.Node} {
</div>
)

return {value, label}
return {...nw, value, label}
}

type NetworkAddressProps = {
Expand Down
4 changes: 4 additions & 0 deletions app/src/http-api-client/networking.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ const STATUS: NetworkingStatusPath = 'networking/status'
const LIST: WifiListPath = 'wifi/list'
const CONFIGURE: WifiConfigurePath = 'wifi/configure'

export const NO_SECURITY: SecurityType = 'none'
export const WPA_PSK_SECURITY: SecurityType = 'wpa-psk'
export const WPA_EAP_SECURITY: SecurityType = 'wpa-eap'

export const fetchNetworkingStatus = buildRequestMaker('GET', STATUS)
export const fetchWifiList = buildRequestMaker('GET', LIST)
export const configureWifi = buildRequestMaker('POST', CONFIGURE)
Expand Down
12 changes: 4 additions & 8 deletions components/src/interaction-enhancers/IntervalWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,14 @@ export default class IntervalWrapper extends React.Component<Props, State> {
render () {
const {children} = this.props

return (
<React.Fragment>
{children}
</React.Fragment>
)
return <React.Fragment>{children}</React.Fragment>
}

componentDidMount () {
const intervalId = setInterval(() => {
this.props.refresh()
}, this.props.interval)
const {refresh, interval} = this.props
const intervalId = setInterval(refresh, interval)
this.setState({intervalId: intervalId})
refresh()
}

componentWillUnmount () {
Expand Down