diff --git a/app/src/components/RobotSettings/ConnectionCard.js b/app/src/components/RobotSettings/ConnectionCard.js index f6bb032d289..2c727f42aab 100644 --- a/app/src/components/RobotSettings/ConnectionCard.js +++ b/app/src/components/RobotSettings/ConnectionCard.js @@ -2,11 +2,10 @@ // RobotSettings card for wifi status import * as React from 'react' import {connect} from 'react-redux' -import {getIn} from '@thi.ng/paths' import find from 'lodash/find' -import {getConfig} from '../../config' import {makeGetRobotNetworkingStatus} from '../../http-api-client' +import {CONNECTABLE} from '../../discovery' import {Card} from '@opentrons/components' import SelectNetwork from './SelectNetwork' import {ConnectionStatusMessage, ConnectionInfo} from './connection' @@ -18,7 +17,6 @@ import type {InternetStatus, NetworkInterface} from '../../http-api-client' type OP = {robot: ViewableRobot} type SP = {| - __featureEnabled: boolean, internetStatus: ?InternetStatus, wifiNetwork: ?NetworkInterface, ethernetNetwork: ?NetworkInterface, @@ -26,27 +24,32 @@ type SP = {| type Props = {...$Exact, ...SP} -const __FEATURE_FLAG = 'devInternal.manageRobotConnection.newCard' - export default connect(makeMapStateToProps)(ConnectionCard) const TITLE = 'Connectivity' function ConnectionCard (props: Props) { - // TODO(mc, 2018-10-15): remove feature flag - if (!props.__featureEnabled) return null - const {robot, internetStatus, wifiNetwork, ethernetNetwork} = props + const disabled = robot.status !== CONNECTABLE return ( - + - + - + ) } @@ -64,7 +67,6 @@ function makeMapStateToProps (): (State, OP) => SP { internetStatus, wifiNetwork: find(interfaces, {type: 'wifi'}), ethernetNetwork: find(interfaces, {type: 'ethernet'}), - __featureEnabled: !!getIn(getConfig(state), __FEATURE_FLAG), } } } diff --git a/app/src/components/RobotSettings/ConnectivityCard.js b/app/src/components/RobotSettings/ConnectivityCard.js deleted file mode 100644 index 872a43fbcc7..00000000000 --- a/app/src/components/RobotSettings/ConnectivityCard.js +++ /dev/null @@ -1,145 +0,0 @@ -// @flow -// RobotSettings card for wifi status -import * as React from 'react' -import {connect} from 'react-redux' - -import {CONNECTABLE, startDiscovery} from '../../discovery' -import { - fetchNetworkingStatus, - fetchWifiList, - configureWifi, - clearConfigureWifiResponse, - makeGetRobotWifiList, - makeGetRobotWifiConfigure, -} from '../../http-api-client' - -import {RefreshCard, LabeledValue} from '@opentrons/components' -import {CardContentFull} from '../layout' -import WifiConnectForm from './WifiConnectForm' -import WifiConnectModal from './WifiConnectModal' - -import type {State, Dispatch} from '../../types' -import type {ViewableRobot} from '../../discovery' -import type {FetchWifiListCall, ConfigureWifiCall} from '../../http-api-client' - -type OP = {robot: ViewableRobot} - -type SP = {| - listRequest: FetchWifiListCall, - configureRequest: ConfigureWifiCall, -|} - -type DP = {| - refresh: () => mixed, - configure: (?string, ?string) => mixed, - clearSuccessfulConfigure: () => mixed, - clearFailedConfigure: () => mixed, -|} - -type Props = {...$Exact, ...SP, ...DP} - -const TITLE = 'Connectivity' -const CONNECTED_BY_LABEL = 'Connected by' - -export default connect( - makeMapStateToProps, - mapDispatchToProps -)(ConnectivityCard) - -function ConnectivityCard (props: Props) { - const { - refresh, - clearSuccessfulConfigure, - clearFailedConfigure, - configure, - robot: {ip, local, name, status}, - listRequest: {response: listResponse}, - configureRequest: { - inProgress: configInProgress, - response: configResponse, - error: configError, - }, - } = props - const disabled = status !== CONNECTABLE - const list = (listResponse && listResponse.list) || [] - - const active = list.find(network => network.active) - const activeSsid = active && active.ssid - const connectedBy = local ? 'USB' : `${activeSsid || ''} (WiFi)` - - const listOptions = list.map(({active, ssid}) => ({ - name: active ? `${ssid} *` : ssid, - value: ssid, - })) - - return ( - - - - - - - - {(!!configError || !!configResponse) && ( - - )} - - ) -} - -function makeMapStateToProps () { - const getWifiList = makeGetRobotWifiList() - const getWifiConfigure = makeGetRobotWifiConfigure() - - return (state: State, ownProps: OP): SP => ({ - listRequest: getWifiList(state, ownProps.robot), - configureRequest: getWifiConfigure(state, ownProps.robot), - }) -} - -function mapDispatchToProps (dispatch: Dispatch, ownProps: OP): DP { - const {robot} = ownProps - const configure = (ssid, psk) => dispatch(configureWifi(robot, {ssid, psk})) - const refresh = () => { - // send these requests simultaneously - dispatch(fetchNetworkingStatus(robot)) - dispatch(fetchWifiList(robot)) - } - - // TODO(mc, 2018-02-26): handle refreshing the list and kicking off dispatch - // more elegantly and closer to the configure response - const clearConfigureAction = clearConfigureWifiResponse(robot) - const clearFailedConfigure = () => dispatch(clearConfigureAction) - const clearSuccessfulConfigure = () => - Promise.resolve() - .then(refresh) - .then(() => dispatch(startDiscovery())) - .then(() => dispatch(clearConfigureAction)) - - return { - refresh, - configure, - clearSuccessfulConfigure, - clearFailedConfigure, - } -} diff --git a/app/src/components/RobotSettings/SelectNetwork/ConnectForm.js b/app/src/components/RobotSettings/SelectNetwork/ConnectForm.js index 095389f7e50..05049492267 100644 --- a/app/src/components/RobotSettings/SelectNetwork/ConnectForm.js +++ b/app/src/components/RobotSettings/SelectNetwork/ConnectForm.js @@ -98,12 +98,17 @@ const UNKNOWN_SECURITY_OPTIONS: Array = [ ] const getEapType = (v: FormValues): ?string => get(v, EAP_TYPE_FIELD) -const makeEapOpt = (o: WifiEapOption) => ({label: o.displayName, value: o.name}) -const makeEapField = (o: WifiAuthField) => ({ - type: o.type, - name: `${EAP_CONFIG_FIELD}.${o.name}`, - label: o.displayName, - required: o.required, + +const makeEapOpt = (opt: WifiEapOption) => ({ + label: opt.displayName || opt.name, + value: opt.name, +}) + +const makeEapField = (opt: WifiAuthField) => ({ + type: opt.type, + name: `${EAP_CONFIG_FIELD}.${opt.name}`, + label: opt.displayName, + required: opt.required, }) const getEapFields = ( diff --git a/app/src/components/RobotSettings/WifiConnectModal.js b/app/src/components/RobotSettings/SelectNetwork/WifiConnectModal.js similarity index 52% rename from app/src/components/RobotSettings/WifiConnectModal.js rename to app/src/components/RobotSettings/SelectNetwork/WifiConnectModal.js index 363bc0944b4..8e2e7c2167f 100644 --- a/app/src/components/RobotSettings/WifiConnectModal.js +++ b/app/src/components/RobotSettings/SelectNetwork/WifiConnectModal.js @@ -3,32 +3,35 @@ import * as React from 'react' import type { + WifiConfigureRequest, WifiConfigureResponse, ApiRequestError, -} from '../../http-api-client' +} from '../../../http-api-client' import {AlertModal} from '@opentrons/components' -import {Portal} from '../portal' -import {ErrorModal} from '../modals' +import {ErrorModal} from '../../modals' type Props = { close: () => mixed, - error: ?ApiRequestError, + request: WifiConfigureRequest, response: ?WifiConfigureResponse, + error: ?ApiRequestError, } -const SUCCESS_TITLE = 'Successfully connected to ' -const FAILURE_TITLE = 'Could not join network' +const SUCCESS_TITLE = 'Successfully connected to Wi-Fi' +const FAILURE_TITLE = 'Unable to connect to Wi-Fi' + +const success = ssid => + `Your robot has successfully connected to Wi-Fi network ${ssid}.` -const SUCCESS_MESSAGE = - 'Your robot has successfully connected to WiFi and should appear in the robot list shortly. If not, try refreshing the list manually or rebooting the robot.' -const FAILURE_MESSAGE = - 'The robot was unable to connect to the selected WiFi network. Please double check your network credentials.' +const failure = ssid => + `Your robot was unable to connect to ${ssid}. Please double-check your network credentials.` const ERROR_MESSAGE_RE = /Error: (.*)$/ export default function WifiConnectModal (props: Props) { - const {response, error, close} = props + const {request, response, error, close} = props + const {ssid} = request if (error || !response) { let errorMessage = 'An unknown error occurred' @@ -47,7 +50,7 @@ export default function WifiConnectModal (props: Props) { return ( @@ -55,16 +58,14 @@ export default function WifiConnectModal (props: Props) { } return ( - - - {SUCCESS_MESSAGE} - - + + {success(ssid)} + ) } diff --git a/app/src/components/RobotSettings/SelectNetwork/index.js b/app/src/components/RobotSettings/SelectNetwork/index.js index ddf70ad9a5a..af290f43ea6 100644 --- a/app/src/components/RobotSettings/SelectNetwork/index.js +++ b/app/src/components/RobotSettings/SelectNetwork/index.js @@ -9,19 +9,25 @@ import { fetchWifiList, fetchWifiEapOptions, fetchWifiKeys, + fetchNetworkingStatus, addWifiKey, configureWifi, makeGetRobotWifiList, makeGetRobotWifiEapOptions, makeGetRobotWifiKeys, makeGetRobotWifiConfigure, + clearConfigureWifiResponse, } from '../../../http-api-client' +import {startDiscovery} from '../../../discovery' +import {chainActions} from '../../../util' + import {IntervalWrapper, SpinnerModal} from '@opentrons/components' import {Portal} from '../../portal' import ConnectModal from './ConnectModal' import ConnectForm from './ConnectForm' import SelectSsid from './SelectSsid' +import WifiConnectModal from './WifiConnectModal' import type {State, Dispatch} from '../../../types' import type {ViewableRobot} from '../../../discovery' @@ -31,6 +37,8 @@ import type { WifiEapOptionsList, WifiKeysList, WifiConfigureRequest, + WifiConfigureResponse, + ApiRequestError, } from '../../../http-api-client' type OP = {robot: ViewableRobot} @@ -40,14 +48,18 @@ type SP = {| connectingTo: ?string, eapOptions: ?WifiEapOptionsList, keys: ?WifiKeysList, + configRequest: ?WifiConfigureRequest, + configResponse: ?WifiConfigureResponse, + configError: ?ApiRequestError, |} type DP = {| - fetchList: () => mixed, fetchEapOptions: () => mixed, fetchKeys: () => mixed, addKey: (file: File) => mixed, configure: WifiConfigureRequest => mixed, + refresh: () => mixed, + clearConfigure: () => mixed, |} type Props = {...$Exact, ...SP, ...DP} @@ -103,14 +115,18 @@ class SelectNetwork extends React.Component { connectingTo, eapOptions, keys, - fetchList, - configure, + refresh, addKey, + configure, + configRequest, + configResponse, + configError, + clearConfigure, } = this.props const {ssid, securityType, modalOpen} = this.state return ( - + { /> )} + {configRequest && + !!(configError || configResponse) && ( + + )} ) @@ -160,6 +185,7 @@ function makeMapStateToProps (): (State, OP) => SP { const { request: cfgRequest, inProgress: cfgInProgress, + response: cfgResponse, error: cfgError, } = getConfigureCall(state, robot) @@ -169,19 +195,32 @@ function makeMapStateToProps (): (State, OP) => SP { keys: keysResponse && keysResponse.keys, connectingTo: !cfgError && cfgInProgress && cfgRequest ? cfgRequest.ssid : null, + configRequest: cfgRequest, + configResponse: cfgResponse, + configError: cfgError, } } } function mapDispatchToProps (dispatch: Dispatch, ownProps: OP): DP { const {robot} = ownProps + const refreshActions = [fetchWifiList(robot), fetchNetworkingStatus(robot)] + const configure = params => + dispatch( + chainActions( + configureWifi(robot, params), + startDiscovery(), + ...refreshActions + ) + ) return { - fetchList: () => dispatch(fetchWifiList(robot)), + configure, + clearConfigure: () => dispatch(clearConfigureWifiResponse(robot)), fetchEapOptions: () => dispatch(fetchWifiEapOptions(robot)), fetchKeys: () => dispatch(fetchWifiKeys(robot)), addKey: file => dispatch(addWifiKey(robot, file)), - configure: params => dispatch(configureWifi(robot, params)), + refresh: () => refreshActions.forEach(dispatch), } } diff --git a/app/src/components/RobotSettings/WifiConnectForm.js b/app/src/components/RobotSettings/WifiConnectForm.js deleted file mode 100644 index 8b1e73bfd8c..00000000000 --- a/app/src/components/RobotSettings/WifiConnectForm.js +++ /dev/null @@ -1,87 +0,0 @@ -// @flow -import * as React from 'react' - -import {OutlineButton, type DropdownOption} from '@opentrons/components' -import {Form, Select, TextInput} from './inputs' -import styles from './styles.css' - -type Props = { - disabled: boolean, - activeSsid: ?string, - networks: Array, - onSubmit: (?string, ?string) => mixed, -} - -type State = { - ssid: ?string, - psk: ?string, -} - -type Update = { - ssid?: string, - psk?: string, -} - -export default class ConfigureWifiForm extends React.Component { - constructor (props: Props) { - super(props) - this.state = {ssid: null, psk: null} - } - - onChange = (update: Update) => this.setState(update) - - onSubmit = () => { - this.props.onSubmit(this.getSsid(), this.state.psk) - this.setState({psk: null}) - } - - getSsid (): ?string { - return this.state.ssid || this.props.activeSsid - } - - render () { - const {activeSsid, networks} = this.props - const {psk} = this.state - const ssid = this.getSsid() - const inputDisabled = this.props.disabled - const formDisabled = inputDisabled || !ssid - - return ( -
-