diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2019-06-27 13:34:55 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2019-06-27 20:01:18 +0200 |
| commit | 55ee652e4ef13faea40d4f202dfa66d77a01c813 (patch) | |
| tree | 32419bf246017da10c03d149a210c96a6d18c09b /gui/src | |
| parent | 7068c166b53b0a24dfcffa2c31c30bd120816938 (diff) | |
| download | mullvadvpn-55ee652e4ef13faea40d4f202dfa66d77a01c813.tar.xz mullvadvpn-55ee652e4ef13faea40d4f202dfa66d77a01c813.zip | |
Refactor connection panel into container
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/Connect.tsx | 52 | ||||
| -rw-r--r-- | gui/src/renderer/components/ConnectionPanel.tsx (renamed from gui/src/renderer/components/ConnectionInfo.tsx) | 95 | ||||
| -rw-r--r-- | gui/src/renderer/components/ConnectionPanelDisclosure.tsx (renamed from gui/src/renderer/components/ConnectionInfoDisclosure.tsx) | 28 | ||||
| -rw-r--r-- | gui/src/renderer/components/TunnelControl.tsx | 51 | ||||
| -rw-r--r-- | gui/src/renderer/containers/ConnectPage.tsx | 10 | ||||
| -rw-r--r-- | gui/src/renderer/containers/ConnectionPanelContainer.tsx | 75 | ||||
| -rw-r--r-- | gui/src/renderer/redux/userinterface/actions.ts | 10 | ||||
| -rw-r--r-- | gui/src/renderer/redux/userinterface/reducers.ts | 8 |
8 files changed, 137 insertions, 192 deletions
diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx index 60fca1df50..b39f09e705 100644 --- a/gui/src/renderer/components/Connect.tsx +++ b/gui/src/renderer/components/Connect.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { Component, Styles, View } from 'reactxp'; import { links } from '../../config.json'; -import { ITunnelEndpoint, parseSocketAddress } from '../../shared/daemon-rpc-types'; import AccountExpiry from '../lib/account-expiry'; import { AuthFailureKind, parseAuthFailure } from '../lib/auth-failure'; import { IConnectionReduxState } from '../redux/connection/reducers'; @@ -12,21 +11,19 @@ import ImageView from './ImageView'; import { Container, Header, Layout } from './Layout'; import Map, { MarkerStyle, ZoomLevel } from './Map'; import NotificationArea from './NotificationArea'; -import TunnelControl, { IBridgeData, IRelayInAddress, IRelayOutAddress } from './TunnelControl'; +import TunnelControl from './TunnelControl'; interface IProps { connection: IConnectionReduxState; version: IVersionReduxState; accountExpiry?: AccountExpiry; selectedRelayName: string; - connectionInfoOpen: boolean; blockWhenDisconnected: boolean; onSettings: () => void; onSelectLocation: () => void; onConnect: () => void; onDisconnect: () => void; onExternalLink: (url: string) => void; - onToggleConnectionInfo: (value: boolean) => void; } type MarkerOrSpinner = 'marker' | 'spinner'; @@ -148,22 +145,6 @@ export default class Connect extends Component<IProps, IState> { } private renderMap() { - const status = this.props.connection.status; - - const relayOutAddress: IRelayOutAddress = { - ipv4: this.props.connection.ipv4, - ipv6: this.props.connection.ipv6, - }; - const relayInAddress: IRelayInAddress | undefined = - (status.state === 'connecting' || status.state === 'connected') && status.details - ? this.tunnelEndpointToRelayInAddress(status.details) - : undefined; - - const bridgeData: IBridgeData | undefined = - (status.state === 'connecting' || status.state === 'connected') && status.details - ? this.tunnelEndpointToBridgeData(status.details) - : undefined; - return ( <View style={styles.connect}> <Map style={styles.map} {...this.getMapProps()} /> @@ -180,16 +161,9 @@ export default class Connect extends Component<IProps, IState> { selectedRelayName={this.props.selectedRelayName} city={this.props.connection.city} country={this.props.connection.country} - hostname={this.props.connection.hostname} - defaultConnectionInfoOpen={this.props.connectionInfoOpen} - relayInAddress={relayInAddress} - bridge={bridgeData} - bridgeHostname={this.props.connection.bridgeHostname} - relayOutAddress={relayOutAddress} onConnect={this.props.onConnect} onDisconnect={this.props.onDisconnect} onSelectLocation={this.props.onSelectLocation} - onToggleConnectionInfo={this.props.onToggleConnectionInfo} /> <NotificationArea @@ -321,28 +295,4 @@ export default class Connect extends Component<IProps, IState> { ? 'spinner' : 'marker'; } - - private tunnelEndpointToRelayInAddress(tunnelEndpoint: ITunnelEndpoint): IRelayInAddress { - const socketAddr = parseSocketAddress(tunnelEndpoint.address); - return { - ip: socketAddr.host, - port: socketAddr.port, - protocol: tunnelEndpoint.protocol, - tunnelType: tunnelEndpoint.tunnelType, - }; - } - - private tunnelEndpointToBridgeData(endpoint: ITunnelEndpoint): IBridgeData | undefined { - if (!endpoint.proxy) { - return undefined; - } - - const socketAddr = parseSocketAddress(endpoint.proxy.address); - return { - ip: socketAddr.host, - port: socketAddr.port, - protocol: endpoint.proxy.protocol, - bridgeType: endpoint.proxy.proxyType, - }; - } } diff --git a/gui/src/renderer/components/ConnectionInfo.tsx b/gui/src/renderer/components/ConnectionPanel.tsx index 2c6796f7fc..9992d3bf73 100644 --- a/gui/src/renderer/components/ConnectionInfo.tsx +++ b/gui/src/renderer/components/ConnectionPanel.tsx @@ -1,10 +1,45 @@ import * as React from 'react'; import { Component, Styles, Text, Types, View } from 'reactxp'; import { sprintf } from 'sprintf-js'; -import { proxyTypeToString, TunnelType, tunnelTypeToString } from '../../shared/daemon-rpc-types'; +import { + ProxyType, + proxyTypeToString, + RelayProtocol, + TunnelType, + tunnelTypeToString, +} from '../../shared/daemon-rpc-types'; import { messages } from '../../shared/gettext'; -import { default as ConnectionInfoDisclosure } from './ConnectionInfoDisclosure'; -import { IBridgeData } from './TunnelControl'; +import { default as ConnectionPanelDisclosure } from '../components/ConnectionPanelDisclosure'; + +export interface IEndpoint { + ip: string; + port: number; + protocol: RelayProtocol; +} + +export interface IInAddress extends IEndpoint { + tunnelType: TunnelType; +} + +export interface IBridgeData extends IEndpoint { + bridgeType: ProxyType; +} + +export interface IOutAddress { + ipv4?: string; + ipv6?: string; +} + +interface IProps { + isOpen: boolean; + hostname?: string; + bridgeHostname?: string; + inAddress?: IInAddress; + bridgeInfo?: IBridgeData; + outAddress?: IOutAddress; + onToggle: () => void; + style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; +} const styles = { row: Styles.createViewStyle({ @@ -32,42 +67,7 @@ const styles = { }), }; -interface IInAddress { - ip: string; - port: number; - protocol: string; - tunnelType: TunnelType; -} - -interface IOutAddress { - ipv4?: string; - ipv6?: string; -} - -interface IProps { - hostname?: string; - bridgeHostname?: string; - inAddress?: IInAddress; - bridgeInfo?: IBridgeData; - outAddress?: IOutAddress; - defaultOpen?: boolean; - style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; - onToggle?: (isOpen: boolean) => void; -} - -interface IState { - isOpen: boolean; -} - -export default class ConnectionInfo extends Component<IProps, IState> { - constructor(props: IProps) { - super(props); - - this.state = { - isOpen: props.defaultOpen === true, - }; - } - +export default class ConnectionPanel extends Component<IProps> { public render() { const { inAddress, outAddress, bridgeInfo } = this.props; const entryPoint = bridgeInfo && inAddress ? bridgeInfo : inAddress; @@ -76,13 +76,13 @@ export default class ConnectionInfo extends Component<IProps, IState> { <View style={this.props.style}> {this.props.hostname && ( <View style={styles.header}> - <ConnectionInfoDisclosure defaultOpen={this.props.defaultOpen} onToggle={this.onToggle}> + <ConnectionPanelDisclosure pointsUp={this.props.isOpen} onToggle={this.props.onToggle}> {this.hostnameLine()} - </ConnectionInfoDisclosure> + </ConnectionPanelDisclosure> </View> )} - {this.state.isOpen && this.props.hostname && ( + {this.props.isOpen && this.props.hostname && ( <React.Fragment> {this.props.inAddress && ( <View style={styles.row}> @@ -159,15 +159,4 @@ export default class ConnectionInfo extends Component<IProps, IState> { return ''; } } - - private onToggle = (isOpen: boolean) => { - this.setState( - (state) => ({ ...state, isOpen }), - () => { - if (this.props.onToggle) { - this.props.onToggle(isOpen); - } - }, - ); - }; } diff --git a/gui/src/renderer/components/ConnectionInfoDisclosure.tsx b/gui/src/renderer/components/ConnectionPanelDisclosure.tsx index 3489a639dd..17c3dc9919 100644 --- a/gui/src/renderer/components/ConnectionInfoDisclosure.tsx +++ b/gui/src/renderer/components/ConnectionPanelDisclosure.tsx @@ -22,41 +22,39 @@ const styles = { }; interface IProps { - onToggle?: (isOpen: boolean) => void; - defaultOpen?: boolean; + pointsUp: boolean; + onToggle?: () => void; children: React.ReactText; style?: Types.ViewStyleRuleSet | Types.ViewStyleRuleSet[]; } interface IState { isHovered: boolean; - isOpen: boolean; } -export default class ConnectionInfoDisclosure extends Component<IProps, IState> { +export default class ConnectionPanelDisclosure extends Component<IProps, IState> { constructor(props: IProps) { super(props); this.state = { isHovered: false, - isOpen: props.defaultOpen === true, }; } public render() { const tintColor = this.state.isHovered ? 'rgb(255, 255, 255)' : 'rgb(255, 255, 255, 0.4)'; const textHoverStyle = - this.state.isOpen || this.state.isHovered ? styles.caption.hovered : undefined; + this.props.pointsUp || this.state.isHovered ? styles.caption.hovered : undefined; return ( <View style={[styles.container, this.props.style]} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} - onPress={this.onToggle}> + onPress={this.props.onToggle}> <Text style={[styles.caption.base, textHoverStyle]}>{this.props.children}</Text> <ImageView - source={this.state.isOpen ? 'icon-chevron-up' : 'icon-chevron-down'} + source={this.props.pointsUp ? 'icon-chevron-up' : 'icon-chevron-down'} width={24} height={24} tintColor={tintColor} @@ -72,18 +70,4 @@ export default class ConnectionInfoDisclosure extends Component<IProps, IState> private onMouseLeave = () => { this.setState({ isHovered: false }); }; - - private onToggle = () => { - this.setState( - (state) => ({ - ...state, - isOpen: !state.isOpen, - }), - () => { - if (this.props.onToggle) { - this.props.onToggle(this.state.isOpen); - } - }, - ); - }; } diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx index ed062c9f0d..ffb7ac2479 100644 --- a/gui/src/renderer/components/TunnelControl.tsx +++ b/gui/src/renderer/components/TunnelControl.tsx @@ -1,51 +1,20 @@ import * as React from 'react'; import { Component, Styles, Text, Types, View } from 'reactxp'; import { colors } from '../../config.json'; -import { - ProxyType, - RelayProtocol, - TunnelStateTransition, - TunnelType, -} from '../../shared/daemon-rpc-types'; +import { TunnelStateTransition } from '../../shared/daemon-rpc-types'; import { cities, countries, messages, relayLocations } from '../../shared/gettext'; +import ConnectionPanelContainer from '../containers/ConnectionPanelContainer'; import * as AppButton from './AppButton'; -import ConnectionInfo from './ConnectionInfo'; import SecuredLabel, { SecuredDisplayStyle } from './SecuredLabel'; -export interface IEndpoint { - ip: string; - port: number; - protocol: RelayProtocol; -} - -export interface IRelayInAddress extends IEndpoint { - tunnelType: TunnelType; -} - -export interface IBridgeData extends IEndpoint { - bridgeType: ProxyType; -} - -export interface IRelayOutAddress { - ipv4?: string; - ipv6?: string; -} - interface ITunnelControlProps { tunnelState: TunnelStateTransition; selectedRelayName: string; city?: string; country?: string; - hostname?: string; - defaultConnectionInfoOpen?: boolean; - relayInAddress?: IRelayInAddress; - relayOutAddress?: IRelayOutAddress; - bridge?: IBridgeData; - bridgeHostname?: string; onConnect: () => void; onDisconnect: () => void; onSelectLocation: () => void; - onToggleConnectionInfo: (value: boolean) => void; } const styles = { @@ -157,18 +126,6 @@ export default class TunnelControl extends Component<ITunnelControlProps> { <View style={styles.footer}>{children}</View> ); - const connectionDetails = ( - <ConnectionInfo - hostname={this.props.hostname} - bridgeHostname={this.props.bridgeHostname} - inAddress={this.props.relayInAddress} - bridgeInfo={this.props.bridge} - outAddress={this.props.relayOutAddress} - defaultOpen={this.props.defaultConnectionInfoOpen} - onToggle={this.props.onToggleConnectionInfo} - /> - ); - let state = this.props.tunnelState.state; switch (this.props.tunnelState.state) { @@ -208,7 +165,7 @@ export default class TunnelControl extends Component<ITunnelControlProps> { <City /> <Country /> </Location> - {connectionDetails} + <ConnectionPanelContainer /> </Body> <Footer> <SwitchLocation /> @@ -225,7 +182,7 @@ export default class TunnelControl extends Component<ITunnelControlProps> { <City /> <Country /> </Location> - {connectionDetails} + <ConnectionPanelContainer /> </Body> <Footer> <SwitchLocation /> diff --git a/gui/src/renderer/containers/ConnectPage.tsx b/gui/src/renderer/containers/ConnectPage.tsx index 2e22ca9fab..3669171f89 100644 --- a/gui/src/renderer/containers/ConnectPage.tsx +++ b/gui/src/renderer/containers/ConnectPage.tsx @@ -11,13 +11,10 @@ import { } from '../../shared/gettext'; import Connect from '../components/Connect'; import AccountExpiry from '../lib/account-expiry'; -import userInterfaceActions from '../redux/userinterface/actions'; - +import { IRelayLocationRedux, RelaySettingsRedux } from '../redux/settings/reducers'; import { IReduxState, ReduxDispatch } from '../redux/store'; import { ISharedRouteProps } from '../routes'; -import { IRelayLocationRedux, RelaySettingsRedux } from '../redux/settings/reducers'; - function getRelayName( relaySettings: RelaySettingsRedux, relayLocations: IRelayLocationRedux[], @@ -79,19 +76,14 @@ const mapStateToProps = (state: IReduxState, props: ISharedRouteProps) => { selectedRelayName: getRelayName(state.settings.relaySettings, state.settings.relayLocations), connection: state.connection, version: state.version, - connectionInfoOpen: state.userInterface.connectionInfoOpen, blockWhenDisconnected: state.settings.blockWhenDisconnected, }; }; const mapDispatchToProps = (dispatch: ReduxDispatch, props: ISharedRouteProps) => { - const userInterface = bindActionCreators(userInterfaceActions, dispatch); const history = bindActionCreators({ push }, dispatch); return { - onToggleConnectionInfo: (isOpen: boolean) => { - userInterface.updateConnectionInfoOpen(isOpen); - }, onSettings: () => { history.push('/settings'); }, diff --git a/gui/src/renderer/containers/ConnectionPanelContainer.tsx b/gui/src/renderer/containers/ConnectionPanelContainer.tsx new file mode 100644 index 0000000000..77b164c65b --- /dev/null +++ b/gui/src/renderer/containers/ConnectionPanelContainer.tsx @@ -0,0 +1,75 @@ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { ITunnelEndpoint, parseSocketAddress } from '../../shared/daemon-rpc-types'; +import ConnectionPanel, { + IBridgeData, + IInAddress, + IOutAddress, +} from '../components/ConnectionPanel'; +import { IReduxState, ReduxDispatch } from '../redux/store'; +import userInterfaceActions from '../redux/userinterface/actions'; + +function tunnelEndpointToRelayInAddress(tunnelEndpoint: ITunnelEndpoint): IInAddress { + const socketAddr = parseSocketAddress(tunnelEndpoint.address); + return { + ip: socketAddr.host, + port: socketAddr.port, + protocol: tunnelEndpoint.protocol, + tunnelType: tunnelEndpoint.tunnelType, + }; +} + +function tunnelEndpointToBridgeData(endpoint: ITunnelEndpoint): IBridgeData | undefined { + if (!endpoint.proxy) { + return undefined; + } + + const socketAddr = parseSocketAddress(endpoint.proxy.address); + return { + ip: socketAddr.host, + port: socketAddr.port, + protocol: endpoint.proxy.protocol, + bridgeType: endpoint.proxy.proxyType, + }; +} + +const mapStateToProps = (state: IReduxState) => { + const status = state.connection.status; + + const outAddress: IOutAddress = { + ipv4: state.connection.ipv4, + ipv6: state.connection.ipv6, + }; + + const inAddress: IInAddress | undefined = + (status.state === 'connecting' || status.state === 'connected') && status.details + ? tunnelEndpointToRelayInAddress(status.details) + : undefined; + + const bridgeInfo: IBridgeData | undefined = + (status.state === 'connecting' || status.state === 'connected') && status.details + ? tunnelEndpointToBridgeData(status.details) + : undefined; + + return { + isOpen: state.userInterface.connectionPanelVisible, + hostname: state.connection.hostname, + bridgeHostname: state.connection.bridgeHostname, + inAddress, + bridgeInfo, + outAddress, + }; +}; + +const mapDispatchToProps = (dispatch: ReduxDispatch) => { + const userInterface = bindActionCreators(userInterfaceActions, dispatch); + + return { + onToggle: userInterface.toggleConnectionPanel, + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(ConnectionPanel); diff --git a/gui/src/renderer/redux/userinterface/actions.ts b/gui/src/renderer/redux/userinterface/actions.ts index 724f53883d..0af66cd365 100644 --- a/gui/src/renderer/redux/userinterface/actions.ts +++ b/gui/src/renderer/redux/userinterface/actions.ts @@ -4,8 +4,7 @@ export interface IUpdateWindowArrowPositionAction { } export interface IUpdateConnectionInfoOpenAction { - type: 'UPDATE_CONNECTION_INFO_OPEN'; - isOpen: boolean; + type: 'TOGGLE_CONNECTION_PANEL'; } export type UserInterfaceAction = @@ -19,11 +18,10 @@ function updateWindowArrowPosition(arrowPosition: number): IUpdateWindowArrowPos }; } -function updateConnectionInfoOpen(isOpen: boolean): IUpdateConnectionInfoOpenAction { +function toggleConnectionPanel(): IUpdateConnectionInfoOpenAction { return { - type: 'UPDATE_CONNECTION_INFO_OPEN', - isOpen, + type: 'TOGGLE_CONNECTION_PANEL', }; } -export default { updateWindowArrowPosition, updateConnectionInfoOpen }; +export default { updateWindowArrowPosition, toggleConnectionPanel }; diff --git a/gui/src/renderer/redux/userinterface/reducers.ts b/gui/src/renderer/redux/userinterface/reducers.ts index 75005fd423..c6e7aafde8 100644 --- a/gui/src/renderer/redux/userinterface/reducers.ts +++ b/gui/src/renderer/redux/userinterface/reducers.ts @@ -2,11 +2,11 @@ import { ReduxAction } from '../store'; export interface IUserInterfaceReduxState { arrowPosition?: number; - connectionInfoOpen: boolean; + connectionPanelVisible: boolean; } const initialState: IUserInterfaceReduxState = { - connectionInfoOpen: false, + connectionPanelVisible: false, }; export default function( @@ -17,8 +17,8 @@ export default function( case 'UPDATE_WINDOW_ARROW_POSITION': return { ...state, arrowPosition: action.arrowPosition }; - case 'UPDATE_CONNECTION_INFO_OPEN': - return { ...state, connectionInfoOpen: action.isOpen }; + case 'TOGGLE_CONNECTION_PANEL': + return { ...state, connectionPanelVisible: !state.connectionPanelVisible }; default: return state; |
