summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2024-01-31 11:48:04 +0100
committerOskar Nyberg <oskar@mullvad.net>2024-01-31 11:48:04 +0100
commit9b9da3ebbd90d52cec84c17edb4d99a472fd9a61 (patch)
tree8138cdc8856e0af7abc6ed6a61b932d00b03ceb1 /gui/src
parent91da61996b0f42789983df924f71a7ead8a1af74 (diff)
parentd954ae0842ccd1f6411fbaa1aecb0bb1df574413 (diff)
downloadmullvadvpn-9b9da3ebbd90d52cec84c17edb4d99a472fd9a61.tar.xz
mullvadvpn-9b9da3ebbd90d52cec84c17edb4d99a472fd9a61.zip
Merge branch 'inform-the-user-when-gui-loses-contact-with-daemon-des-238'
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/index.ts7
-rw-r--r--gui/src/main/notification-controller.ts9
-rw-r--r--gui/src/renderer/components/Launch.tsx91
-rw-r--r--gui/src/renderer/components/Modal.tsx6
-rw-r--r--gui/src/renderer/components/NotificationArea.tsx14
-rw-r--r--gui/src/shared/notifications/daemon-disconnected.ts22
-rw-r--r--gui/src/shared/notifications/notification.ts1
7 files changed, 123 insertions, 27 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 37f6eaa590..635b0ad79e 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -623,6 +623,13 @@ class ApplicationMain
// Reset the daemon event listener since it's going to be invalidated on disconnect
this.daemonEventListener = undefined;
+ if (this.tunnelState.tunnelState.state !== 'disconnected') {
+ this.notificationController.notifyDaemonDisconnected(
+ this.userInterface?.isWindowVisible() ?? false,
+ this.settings.gui.enableSystemNotifications,
+ );
+ }
+
this.tunnelState.resetFallback();
if (wasConnected) {
diff --git a/gui/src/main/notification-controller.ts b/gui/src/main/notification-controller.ts
index 8751ecb6ae..3639ac25eb 100644
--- a/gui/src/main/notification-controller.ts
+++ b/gui/src/main/notification-controller.ts
@@ -7,6 +7,7 @@ import log from '../shared/logging';
import {
ConnectedNotificationProvider,
ConnectingNotificationProvider,
+ DaemonDisconnectedNotificationProvider,
DisconnectedNotificationProvider,
ErrorNotificationProvider,
NotificationAction,
@@ -120,6 +121,14 @@ export default class NotificationController {
return false;
}
+ public notifyDaemonDisconnected(windowVisible: boolean, infoNotificationsEnabled: boolean) {
+ this.notify(
+ new DaemonDisconnectedNotificationProvider().getSystemNotification(),
+ windowVisible,
+ infoNotificationsEnabled,
+ );
+ }
+
// Closes still relevant notifications but still lets them affect notification dot in tray icon.
public dismissActiveNotifications() {
this.activeNotifications.forEach((notification) => {
diff --git a/gui/src/renderer/components/Launch.tsx b/gui/src/renderer/components/Launch.tsx
index 3f86e4d19c..05bf6aeda6 100644
--- a/gui/src/renderer/components/Launch.tsx
+++ b/gui/src/renderer/components/Launch.tsx
@@ -4,15 +4,20 @@ import styled from 'styled-components';
import { colors } from '../../config.json';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
+import { transitions, useHistory } from '../lib/history';
+import { RoutePath } from '../lib/routes';
+import { useBoolean } from '../lib/utilityHooks';
import { useSelector } from '../redux/store';
import * as AppButton from './AppButton';
import { measurements, tinyText } from './common-styles';
import ErrorView from './ErrorView';
import { Footer } from './Layout';
+import { ModalAlert, ModalMessage, ModalMessageList } from './Modal';
+import { ModalAlertType } from './Modal';
export default function Launch() {
const daemonAllowed = useSelector((state) => state.userInterface.daemonAllowed);
- const footer = <SettingsFooter show={daemonAllowed === false} />;
+ const footer = daemonAllowed === false ? <MacOsPermissionFooter /> : <DefaultFooter />;
return (
<ErrorView footer={footer}>
@@ -21,14 +26,13 @@ export default function Launch() {
);
}
-const StyledFooter = styled(Footer)<{ $show: boolean }>((props) => ({
+const StyledFooter = styled(Footer)({
backgroundColor: colors.blue,
padding: `0 14px ${measurements.viewMargin}`,
- opacity: props.$show ? 1 : 0,
transition: 'opacity 250ms ease-in-out',
-}));
+});
-const StyledSystemSettingsContainer = styled.div({
+const StyledFooterInner = styled.div({
display: 'flex',
flexDirection: 'column',
flex: 1,
@@ -38,16 +42,12 @@ const StyledSystemSettingsContainer = styled.div({
padding: '16px',
});
-const StyledLaunchFooterPrompt = styled.span(tinyText, {
+const StyledFooterMessage = styled.span(tinyText, {
color: colors.white,
margin: `8px 0 ${measurements.buttonVerticalMargin} 0`,
});
-interface ISettingsFooterProps {
- show: boolean;
-}
-
-function SettingsFooter(props: ISettingsFooterProps) {
+function MacOsPermissionFooter() {
const { showLaunchDaemonSettings } = useAppContext();
const openSettings = useCallback(async () => {
@@ -55,18 +55,77 @@ function SettingsFooter(props: ISettingsFooterProps) {
}, []);
return (
- <StyledFooter $show={props.show}>
- <StyledSystemSettingsContainer>
- <StyledLaunchFooterPrompt>
+ <StyledFooter>
+ <StyledFooterInner>
+ <StyledFooterMessage>
{messages.pgettext(
'launch-view',
'Permission for the Mullvad VPN service has been revoked. Please go to System Settings and allow Mullvad VPN under the “Allow in the Background” setting.',
)}
- </StyledLaunchFooterPrompt>
+ </StyledFooterMessage>
<AppButton.BlueButton onClick={openSettings}>
{messages.gettext('Go to System Settings')}
</AppButton.BlueButton>
- </StyledSystemSettingsContainer>
+ </StyledFooterInner>
</StyledFooter>
);
}
+
+function DefaultFooter() {
+ const history = useHistory();
+ const [dialogVisible, showDialog, hideDialog] = useBoolean();
+
+ const openSendProblemReport = useCallback(() => {
+ hideDialog();
+ history.push(RoutePath.problemReport, { transition: transitions.show });
+ }, [hideDialog, history.push]);
+
+ return (
+ <>
+ <StyledFooter>
+ <StyledFooterInner>
+ <StyledFooterMessage>
+ {messages.pgettext(
+ 'launch-view',
+ 'Unable to contact the Mullvad system service, your connection might be unsecure. Please troubleshoot or send a problem report by clicking the Learn more button.',
+ )}
+ </StyledFooterMessage>
+ <AppButton.BlueButton onClick={showDialog}>
+ {messages.gettext('Learn more')}
+ </AppButton.BlueButton>
+ </StyledFooterInner>
+ </StyledFooter>
+ <ModalAlert
+ isOpen={dialogVisible}
+ type={ModalAlertType.info}
+ close={hideDialog}
+ buttons={[
+ <AppButton.GreenButton key="problem-report" onClick={openSendProblemReport}>
+ {messages.pgettext('launch-view', 'Send problem report')}
+ </AppButton.GreenButton>,
+ <AppButton.BlueButton key="back" onClick={hideDialog}>
+ {messages.gettext('Back')}
+ </AppButton.BlueButton>,
+ ]}>
+ <ModalMessage>
+ {messages.pgettext(
+ 'launch-view',
+ 'The system service component of the app hasn’t started or can’t be contacted. The system service is responsible for the security, kill switch, and the VPN tunnel. To troubleshoot please try:',
+ )}
+ </ModalMessage>
+ <ModalMessage>
+ <ModalMessageList>
+ <li>{messages.pgettext('launch-view', 'Restarting your computer.')}</li>
+ <li>{messages.pgettext('launch-view', 'Reinstalling the app.')}</li>
+ </ModalMessageList>
+ </ModalMessage>
+ <ModalMessage>
+ {messages.pgettext(
+ 'launch-view',
+ 'If these steps do not work please send a problem report.',
+ )}
+ </ModalMessage>
+ </ModalAlert>
+ </>
+ );
+}
diff --git a/gui/src/renderer/components/Modal.tsx b/gui/src/renderer/components/Modal.tsx
index 2fd676a4ae..1b83e10597 100644
--- a/gui/src/renderer/components/Modal.tsx
+++ b/gui/src/renderer/components/Modal.tsx
@@ -365,3 +365,9 @@ export const ModalMessage = styled.span(tinyText, {
marginTop: '6px',
},
});
+
+export const ModalMessageList = styled.ul({
+ listStyle: 'disc outside',
+ paddingLeft: '20px',
+ color: colors.white80,
+});
diff --git a/gui/src/renderer/components/NotificationArea.tsx b/gui/src/renderer/components/NotificationArea.tsx
index 9bce47eea6..a2a89bcd84 100644
--- a/gui/src/renderer/components/NotificationArea.tsx
+++ b/gui/src/renderer/components/NotificationArea.tsx
@@ -1,8 +1,6 @@
import { useCallback, useState } from 'react';
import { useSelector } from 'react-redux';
-import styled from 'styled-components';
-import { colors } from '../../config.json';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { NewDeviceNotificationProvider } from '../../shared/notifications/new-device';
@@ -27,7 +25,7 @@ import { RoutePath } from '../lib/routes';
import accountActions from '../redux/account/actions';
import { IReduxState } from '../redux/store';
import * as AppButton from './AppButton';
-import { ModalAlert, ModalAlertType, ModalMessage } from './Modal';
+import { ModalAlert, ModalAlertType, ModalMessage, ModalMessageList } from './Modal';
import {
NotificationActions,
NotificationBanner,
@@ -115,12 +113,6 @@ export default function NotificationArea(props: IProps) {
return <NotificationBanner className={props.className} aria-hidden={true} />;
}
-const TroubleshootList = styled.ul({
- listStyle: 'disc outside',
- paddingLeft: '20px',
- color: colors.white80,
-});
-
interface INotificationActionWrapperProps {
action: InAppNotificationAction;
}
@@ -193,11 +185,11 @@ function NotificationActionWrapper(props: INotificationActionWrapperProps) {
close={closeTroubleshootInfo}>
<ModalMessage>{troubleshootInfo?.details}</ModalMessage>
<ModalMessage>
- <TroubleshootList>
+ <ModalMessageList>
{troubleshootInfo?.steps.map((step) => (
<li key={step}>{step}</li>
))}
- </TroubleshootList>
+ </ModalMessageList>
</ModalMessage>
<ModalMessage>
{messages.pgettext(
diff --git a/gui/src/shared/notifications/daemon-disconnected.ts b/gui/src/shared/notifications/daemon-disconnected.ts
new file mode 100644
index 0000000000..50a62266d0
--- /dev/null
+++ b/gui/src/shared/notifications/daemon-disconnected.ts
@@ -0,0 +1,22 @@
+import { messages } from '../../shared/gettext';
+import {
+ SystemNotification,
+ SystemNotificationCategory,
+ SystemNotificationProvider,
+ SystemNotificationSeverityType,
+} from './notification';
+
+export class DaemonDisconnectedNotificationProvider implements SystemNotificationProvider {
+ public mayDisplay = () => true;
+
+ public getSystemNotification(): SystemNotification {
+ return {
+ message: messages.pgettext(
+ 'notifications',
+ 'Connection might be unsecured. App lost contact with system service, please troubleshoot.',
+ ),
+ severity: SystemNotificationSeverityType.high,
+ category: SystemNotificationCategory.tunnelState,
+ };
+ }
+}
diff --git a/gui/src/shared/notifications/notification.ts b/gui/src/shared/notifications/notification.ts
index b8727739ef..1957cc07fb 100644
--- a/gui/src/shared/notifications/notification.ts
+++ b/gui/src/shared/notifications/notification.ts
@@ -72,6 +72,7 @@ export * from './block-when-disconnected';
export * from './connected';
export * from './connecting';
export * from './disconnected';
+export * from './daemon-disconnected';
export * from './error';
export * from './inconsistent-version';
export * from './reconnecting';