diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-12-21 14:59:29 -0200 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-12-21 14:59:29 -0200 |
| commit | 8a040750449c381fc47d5dc66e8757e0661717ff (patch) | |
| tree | 5baf4fa6818ad06d5e2d3f1f8d9eaac0fa9b01c3 | |
| parent | 11f6f8e7c9be27f18e674e21171ee2b87b05efce (diff) | |
| parent | d492a764901f0ce8de26c4ad6452762d6be806b1 (diff) | |
| download | mullvadvpn-8a040750449c381fc47d5dc66e8757e0661717ff.tar.xz mullvadvpn-8a040750449c381fc47d5dc66e8757e0661717ff.zip | |
Merge branch 'disable-buttons-when-offline'
11 files changed, 48 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f4bb2ec365..bb15d1c4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ Line wrap the file at 100 chars. Th - Add a toggle switch to allow the app to start minimized on Linux, so that only the tray icon is initially visible. +### Changed +- Disable buttons and menus that open external links when the app knows that there is no internet + connection. + ### Fixed - Stop GUI from glitching during the short reconnect state. - Dismiss notifications automatically after four seconds in all platforms. diff --git a/gui/packages/desktop/src/renderer/components/Account.js b/gui/packages/desktop/src/renderer/components/Account.js index 8db9887993..6d5c537f92 100644 --- a/gui/packages/desktop/src/renderer/components/Account.js +++ b/gui/packages/desktop/src/renderer/components/Account.js @@ -15,6 +15,7 @@ type Props = { accountToken: AccountToken, accountExpiry: ?string, expiryLocale: string, + isOffline: boolean, onLogout: () => void, onClose: () => void, onBuyMore: () => void, @@ -58,6 +59,7 @@ export default class Account extends Component<Props> { <View style={styles.account__footer}> <AppButton.GreenButton style={styles.account__buy_button} + disabled={this.props.isOffline} onPress={this.props.onBuyMore} text="Buy more credit" icon="icon-extLink" diff --git a/gui/packages/desktop/src/renderer/components/Connect.js b/gui/packages/desktop/src/renderer/components/Connect.js index 577f4e470a..345812cf8e 100644 --- a/gui/packages/desktop/src/renderer/components/Connect.js +++ b/gui/packages/desktop/src/renderer/components/Connect.js @@ -63,6 +63,8 @@ export default class Connect extends Component<Props> { message = 'Your internet connection will be secured when you get back online'; } + const { isBlocked } = this.props.connection; + return ( <View style={styles.connect}> <View style={styles.status_icon}> @@ -73,7 +75,9 @@ export default class Connect extends Component<Props> { <View style={styles.error_message}>{message}</View> {error instanceof NoCreditError ? ( <View> - <AppButton.GreenButton onPress={() => this.props.onExternalLink('purchase')}> + <AppButton.GreenButton + disabled={isBlocked} + onPress={() => this.props.onExternalLink('purchase')}> <AppButton.Label>Buy more time</AppButton.Label> <ImageView source="icon-extLink" height={16} width={16} /> </AppButton.GreenButton> diff --git a/gui/packages/desktop/src/renderer/components/Settings.js b/gui/packages/desktop/src/renderer/components/Settings.js index 3cc82884f1..0a056c92de 100644 --- a/gui/packages/desktop/src/renderer/components/Settings.js +++ b/gui/packages/desktop/src/renderer/components/Settings.js @@ -25,6 +25,7 @@ type Props = { appVersion: string, consistentVersion: boolean, upToDateVersion: boolean, + isOffline: boolean, onQuit: () => void, onClose: () => void, onViewAccount: () => void, @@ -147,6 +148,7 @@ export default class Settings extends Component<Props> { return ( <View> <Cell.CellButton + disabled={this.props.isOffline} onPress={this.props.onExternalLink.bind(this, 'download')} testName="settings__version"> {icon} @@ -168,6 +170,7 @@ export default class Settings extends Component<Props> { </Cell.CellButton> <Cell.CellButton + disabled={this.props.isOffline} onPress={this.props.onExternalLink.bind(this, 'faq')} testName="settings__external_link"> <Cell.Label>{'FAQs & Guides'}</Cell.Label> diff --git a/gui/packages/desktop/src/renderer/components/Support.js b/gui/packages/desktop/src/renderer/components/Support.js index cdc0346fee..7db2f7458b 100644 --- a/gui/packages/desktop/src/renderer/components/Support.js +++ b/gui/packages/desktop/src/renderer/components/Support.js @@ -21,6 +21,7 @@ export type SupportProps = { defaultEmail: string, defaultMessage: string, accountHistory: Array<AccountToken>, + isOffline: boolean, onClose: () => void, viewLog: (path: string) => void, saveReportForm: (form: SupportReportForm) => void, @@ -250,7 +251,7 @@ export default class Support extends Component<SupportProps, SupportState> { <ImageView source="icon-extLink" height={16} width={16} /> </AppButton.BlueButton> <AppButton.GreenButton - disabled={!this.validate()} + disabled={!this.validate() || this.props.isOffline} onPress={this.onSend} testName="support__send_logs"> Send diff --git a/gui/packages/desktop/src/renderer/containers/AccountPage.js b/gui/packages/desktop/src/renderer/containers/AccountPage.js index fc9d5394be..94cb653d81 100644 --- a/gui/packages/desktop/src/renderer/containers/AccountPage.js +++ b/gui/packages/desktop/src/renderer/containers/AccountPage.js @@ -14,6 +14,7 @@ const mapStateToProps = (state: ReduxState) => ({ accountToken: state.account.accountToken, accountExpiry: state.account.expiry, expiryLocale: remote.app.getLocale(), + isOffline: state.connection.isBlocked, }); const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => { const history = bindActionCreators({ goBack }, dispatch); diff --git a/gui/packages/desktop/src/renderer/containers/SettingsPage.js b/gui/packages/desktop/src/renderer/containers/SettingsPage.js index 8913e79fcd..c37b7f5f4c 100644 --- a/gui/packages/desktop/src/renderer/containers/SettingsPage.js +++ b/gui/packages/desktop/src/renderer/containers/SettingsPage.js @@ -16,6 +16,7 @@ const mapStateToProps = (state: ReduxState) => ({ appVersion: state.version.current, consistentVersion: state.version.consistent, upToDateVersion: state.version.upToDate, + isOffline: state.connection.isBlocked, }); const mapDispatchToProps = (dispatch: ReduxDispatch, _props: SharedRouteProps) => { const history = bindActionCreators({ push, goBack }, dispatch); diff --git a/gui/packages/desktop/src/renderer/containers/SupportPage.js b/gui/packages/desktop/src/renderer/containers/SupportPage.js index 4bc21800cd..86d9f976aa 100644 --- a/gui/packages/desktop/src/renderer/containers/SupportPage.js +++ b/gui/packages/desktop/src/renderer/containers/SupportPage.js @@ -15,6 +15,7 @@ const mapStateToProps = (state: ReduxState) => ({ defaultEmail: state.support.email, defaultMessage: state.support.message, accountHistory: state.account.accountHistory, + isOffline: state.connection.isBlocked, }); const mapDispatchToProps = (dispatch: ReduxDispatch, _props: SharedRouteProps) => { diff --git a/gui/packages/desktop/src/renderer/redux/connection/reducers.js b/gui/packages/desktop/src/renderer/redux/connection/reducers.js index ab9c8df75c..dac8d63209 100644 --- a/gui/packages/desktop/src/renderer/redux/connection/reducers.js +++ b/gui/packages/desktop/src/renderer/redux/connection/reducers.js @@ -6,6 +6,7 @@ import type { TunnelStateTransition, Ip } from '../../lib/daemon-rpc-proxy'; export type ConnectionReduxState = { status: TunnelStateTransition, isOnline: boolean, + isBlocked: boolean, ip: ?Ip, latitude: ?number, longitude: ?number, @@ -16,6 +17,7 @@ export type ConnectionReduxState = { const initialState: ConnectionReduxState = { status: { state: 'disconnected' }, isOnline: true, + isBlocked: false, ip: null, latitude: null, longitude: null, @@ -32,19 +34,31 @@ export default function( return { ...state, ...action.newLocation }; case 'CONNECTING': - return { ...state, status: { state: 'connecting', details: action.tunnelEndpoint } }; + return { + ...state, + status: { state: 'connecting', details: action.tunnelEndpoint }, + isBlocked: true, + }; case 'CONNECTED': - return { ...state, status: { state: 'connected', details: action.tunnelEndpoint } }; + return { + ...state, + status: { state: 'connected', details: action.tunnelEndpoint }, + isBlocked: false, + }; case 'DISCONNECTED': - return { ...state, status: { state: 'disconnected' } }; + return { ...state, status: { state: 'disconnected' }, isBlocked: false }; case 'DISCONNECTING': - return { ...state, status: { state: 'disconnecting', details: action.afterDisconnect } }; + return { + ...state, + status: { state: 'disconnecting', details: action.afterDisconnect }, + isBlocked: true, + }; case 'BLOCKED': - return { ...state, status: { state: 'blocked', details: action.reason } }; + return { ...state, status: { state: 'blocked', details: action.reason }, isBlocked: true }; case 'ONLINE': return { ...state, isOnline: true }; diff --git a/gui/packages/desktop/test/components/Account.spec.js b/gui/packages/desktop/test/components/Account.spec.js index 4813f3d20e..4868b6bab6 100644 --- a/gui/packages/desktop/test/components/Account.spec.js +++ b/gui/packages/desktop/test/components/Account.spec.js @@ -13,6 +13,7 @@ describe('components/Account', () => { accountToken: '1234', accountExpiry: new Date('2038-01-01').toISOString(), expiryLocale: 'en-US', + isOffline: false, updateAccountExpiry: () => Promise.resolve(), onClose: () => {}, onLogout: () => {}, diff --git a/gui/packages/desktop/test/components/Support.spec.js b/gui/packages/desktop/test/components/Support.spec.js index 00da33c634..c51c585f62 100644 --- a/gui/packages/desktop/test/components/Support.spec.js +++ b/gui/packages/desktop/test/components/Support.spec.js @@ -100,6 +100,14 @@ describe('components/Support', () => { await click(sendButton); expect(props.clearReportForm).to.have.been.called.once; }); + + it('should not allow sending when off-line', () => { + const props = makeProps({ isOffline: true }); + const component = shallow(<Support {...props} />); + const sendButton = component.find({ testName: 'support__send_logs' }); + + expect(sendButton.prop('disabled')).to.be.true; + }); }); function makeProps(mergeProps: $Shape<SupportProps> = {}): SupportProps { @@ -107,6 +115,7 @@ function makeProps(mergeProps: $Shape<SupportProps> = {}): SupportProps { defaultEmail: '', defaultMessage: '', accountHistory: [], + isOffline: false, onClose: () => {}, viewLog: (_path) => {}, collectProblemReport: () => Promise.resolve('/path/to/problem/report'), |
