diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2023-02-20 13:45:44 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2023-02-21 18:45:59 +0100 |
| commit | 934bedf2908013ce78d6f00ed7f0d03ab7acd7c4 (patch) | |
| tree | 221e9d9035550be21f05e2be45dc633a7cebce59 /gui/src | |
| parent | 4ecd849bd1004d9b7a8bb5cf57ce2d0e7b58855e (diff) | |
| download | mullvadvpn-934bedf2908013ce78d6f00ed7f0d03ab7acd7c4.tar.xz mullvadvpn-934bedf2908013ce78d6f00ed7f0d03ab7acd7c4.zip | |
Add troubleshoot dialog
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/NotificationArea.tsx | 97 | ||||
| -rw-r--r-- | gui/src/renderer/components/NotificationBanner.tsx | 37 | ||||
| -rw-r--r-- | gui/src/shared/notifications/error.ts | 54 | ||||
| -rw-r--r-- | gui/src/shared/notifications/notification.ts | 10 |
4 files changed, 156 insertions, 42 deletions
diff --git a/gui/src/renderer/components/NotificationArea.tsx b/gui/src/renderer/components/NotificationArea.tsx index 317cc1e923..4923bacc7c 100644 --- a/gui/src/renderer/components/NotificationArea.tsx +++ b/gui/src/renderer/components/NotificationArea.tsx @@ -1,21 +1,29 @@ -import { useCallback } from 'react'; +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 { BlockWhenDisconnectedNotificationProvider, CloseToAccountExpiryNotificationProvider, ConnectingNotificationProvider, ErrorNotificationProvider, + InAppNotificationAction, InAppNotificationProvider, + InAppNotificationTroubleshootInfo, InconsistentVersionNotificationProvider, - NotificationAction, ReconnectingNotificationProvider, UnsupportedVersionNotificationProvider, UpdateAvailableNotificationProvider, } from '../../shared/notifications/notification'; import { useAppContext } from '../context'; +import { transitions, useHistory } from '../lib/history'; +import { RoutePath } from '../lib/routes'; import { IReduxState } from '../redux/store'; +import * as AppButton from './AppButton'; +import { ModalAlert, ModalAlertType, ModalMessage } from './Modal'; import { NotificationActions, NotificationBanner, @@ -24,6 +32,7 @@ import { NotificationOpenLinkAction, NotificationSubtitle, NotificationTitle, + NotificationTroubleshootDialogAction, } from './NotificationBanner'; interface IProps { @@ -92,24 +101,92 @@ 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: NotificationAction; + action: InAppNotificationAction; } function NotificationActionWrapper(props: INotificationActionWrapperProps) { + const history = useHistory(); const { openLinkWithAuth, openUrl } = useAppContext(); + const [troubleshootInfo, setTroubleshootInfo] = useState<InAppNotificationTroubleshootInfo>(); const handleClick = useCallback(() => { - if (props.action.withAuth) { - return openLinkWithAuth(props.action.url); - } else { - return openUrl(props.action.url); + if (props.action) { + switch (props.action.type) { + case 'open-url': + if (props.action.withAuth) { + return openLinkWithAuth(props.action.url); + } else { + return openUrl(props.action.url); + } + case 'troubleshoot-dialog': + setTroubleshootInfo(props.action.troubleshoot); + break; + } } + + return Promise.resolve(); + }, [props.action]); + + const goToProblemReport = useCallback(() => { + setTroubleshootInfo(undefined); + history.push(RoutePath.problemReport, { transition: transitions.show }); }, []); + const closeTroubleshootInfo = useCallback(() => setTroubleshootInfo(undefined), []); + + let actionComponent: React.ReactElement | undefined; + if (props.action) { + switch (props.action.type) { + case 'open-url': + actionComponent = <NotificationOpenLinkAction onClick={handleClick} />; + break; + case 'troubleshoot-dialog': + actionComponent = ( + <> + <NotificationTroubleshootDialogAction onClick={handleClick} /> + </> + ); + break; + } + } + return ( - <NotificationActions> - <NotificationOpenLinkAction onClick={handleClick} /> - </NotificationActions> + <> + <NotificationActions>{actionComponent}</NotificationActions> + <ModalAlert + isOpen={troubleshootInfo !== undefined} + type={ModalAlertType.info} + buttons={[ + <AppButton.GreenButton key="problem-report" onClick={goToProblemReport}> + {messages.pgettext('in-app-notifications', 'Send problem report')} + </AppButton.GreenButton>, + <AppButton.BlueButton key="back" onClick={closeTroubleshootInfo}> + {messages.gettext('Back')} + </AppButton.BlueButton>, + ]} + close={closeTroubleshootInfo}> + <ModalMessage>{troubleshootInfo?.details}</ModalMessage> + <ModalMessage> + <TroubleshootList> + {troubleshootInfo?.steps.map((step) => ( + <li key={step}>{step}</li> + ))} + </TroubleshootList> + </ModalMessage> + <ModalMessage> + {messages.pgettext( + 'troubleshoot', + 'If these steps do not work please send a problem report.', + )} + </ModalMessage> + </ModalAlert> + </> ); } diff --git a/gui/src/renderer/components/NotificationBanner.tsx b/gui/src/renderer/components/NotificationBanner.tsx index 9f8c63e4b2..4f20d315c8 100644 --- a/gui/src/renderer/components/NotificationBanner.tsx +++ b/gui/src/renderer/components/NotificationBanner.tsx @@ -26,7 +26,7 @@ export function NotificationSubtitle(props: INotificationSubtitleProps) { return React.Children.count(props.children) > 0 ? <NotificationSubtitleText {...props} /> : null; } -export const NotificationOpenLinkActionButton = styled(AppButton.SimpleButton)({ +export const NotificationActionButton = styled(AppButton.SimpleButton)({ flex: 1, justifyContent: 'center', cursor: 'default', @@ -36,20 +36,25 @@ export const NotificationOpenLinkActionButton = styled(AppButton.SimpleButton)({ }); export const NotificationOpenLinkActionIcon = styled(ImageView)({ - [NotificationOpenLinkActionButton + ':hover &']: { + [NotificationActionButton + ':hover &']: { + backgroundColor: colors.white80, + }, +}); + +export const NotificationTroubleshootDialogActionIcon = styled(ImageView)({ + [NotificationActionButton + ':hover &']: { backgroundColor: colors.white80, }, }); interface INotifcationOpenLinkActionProps { onClick: () => Promise<void>; - children?: React.ReactNode; } export function NotificationOpenLinkAction(props: INotifcationOpenLinkActionProps) { return ( <AppButton.BlockingButton onClick={props.onClick}> - <NotificationOpenLinkActionButton + <NotificationActionButton aria-describedby={NOTIFICATION_AREA_ID} aria-label={messages.gettext('Open URL')}> <NotificationOpenLinkActionIcon @@ -58,11 +63,33 @@ export function NotificationOpenLinkAction(props: INotifcationOpenLinkActionProp tintColor={colors.white60} source="icon-extLink" /> - </NotificationOpenLinkActionButton> + </NotificationActionButton> </AppButton.BlockingButton> ); } +interface INotifcationTroubleshootDialogActionProps { + onClick: () => Promise<void>; +} + +export function NotificationTroubleshootDialogAction( + props: INotifcationTroubleshootDialogActionProps, +) { + return ( + <NotificationActionButton + aria-describedby={NOTIFICATION_AREA_ID} + aria-label={messages.gettext('Troubleshoot')} + onClick={props.onClick}> + <NotificationOpenLinkActionIcon + height={12} + width={12} + tintColor={colors.white60} + source="icon-info" + /> + </NotificationActionButton> + ); +} + export const NotificationContent = styled.div.attrs({ id: NOTIFICATION_AREA_ID })({ display: 'flex', flexDirection: 'column', diff --git a/gui/src/shared/notifications/error.ts b/gui/src/shared/notifications/error.ts index 4970fccbaa..9ca0921bf6 100644 --- a/gui/src/shared/notifications/error.ts +++ b/gui/src/shared/notifications/error.ts @@ -211,15 +211,17 @@ function getActions(errorState: ErrorState): InAppNotificationAction | void { if (errorState.cause === ErrorStateCause.setFirewallPolicyError && platform === 'linux') { return { - type: 'info-dialog', - details: messages.pgettext( - 'troubleshoot', - 'This can happen because the kernel is old, or if you have removed a kernel.', - ), - troubleshoot: [ - messages.pgettext('troubleshoot', 'Update your kernel.'), - messages.pgettext('troubleshoot', 'Make sure you have NF tables support.'), - ], + type: 'troubleshoot-dialog', + troubleshoot: { + details: messages.pgettext( + 'troubleshoot', + 'This can happen because the kernel is old, or if you have removed a kernel.', + ), + steps: [ + messages.pgettext('troubleshoot', 'Update your kernel.'), + messages.pgettext('troubleshoot', 'Make sure you have NF tables support.'), + ], + }, }; } else if (errorState.cause === ErrorStateCause.setDnsError) { const troubleshootSteps = []; @@ -244,24 +246,28 @@ function getActions(errorState: ErrorState): InAppNotificationAction | void { } return { - type: 'info-dialog', - details: messages.pgettext( - 'troubleshoot', - 'This error can happen when something other than Mullvad is actively updating the DNS.', - ), - troubleshoot: troubleshootSteps, + type: 'troubleshoot-dialog', + troubleshoot: { + details: messages.pgettext( + 'troubleshoot', + 'This error can happen when something other than Mullvad is actively updating the DNS.', + ), + steps: troubleshootSteps, + }, }; } else if (errorState.cause === ErrorStateCause.splitTunnelError) { return { - type: 'info-dialog', - details: messages.pgettext( - 'troubleshoot', - 'Unable to communicate with Mullvad kernel driver.', - ), - troubleshoot: [ - messages.pgettext('troubleshoot', 'Try reconnecting.'), - messages.pgettext('troubleshoot', 'Try restarting your device.'), - ], + type: 'troubleshoot-dialog', + troubleshoot: { + details: messages.pgettext( + 'troubleshoot', + 'Unable to communicate with Mullvad kernel driver.', + ), + steps: [ + messages.pgettext('troubleshoot', 'Try reconnecting.'), + messages.pgettext('troubleshoot', 'Try restarting your device.'), + ], + }, }; } } diff --git a/gui/src/shared/notifications/notification.ts b/gui/src/shared/notifications/notification.ts index 5264dd7305..88bddfa9f5 100644 --- a/gui/src/shared/notifications/notification.ts +++ b/gui/src/shared/notifications/notification.ts @@ -5,12 +5,16 @@ export type NotificationAction = { withAuth?: boolean; }; +export interface InAppNotificationTroubleshootInfo { + details: string; + steps: string[]; +} + export type InAppNotificationAction = | NotificationAction | { - type: 'info-dialog'; - details: string; - troubleshoot: string[]; + type: 'troubleshoot-dialog'; + troubleshoot: InAppNotificationTroubleshootInfo; }; export type InAppNotificationIndicatorType = 'success' | 'warning' | 'error'; |
