Skip to content

Commit 01102af

Browse files
Merge branch 'implement-openvpn-warnings-des-1583'
2 parents 1cb64dd + 306a5a8 commit 01102af

File tree

11 files changed

+420
-45
lines changed

11 files changed

+420
-45
lines changed

desktop/packages/mullvad-vpn/locales/messages.pot

+82
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,17 @@ msgctxt "accessibility"
324324
msgid "Forget account number %(accountNumber)s"
325325
msgstr ""
326326

327+
#. Accessibility label for link to blog post about OpenVPN support ending.
328+
msgctxt "accessibility"
329+
msgid "Go to blog post to read more, opens externally"
330+
msgstr ""
331+
332+
#. Accessibility label for link to VPN settings where
333+
#. the user can change tunnel protocol.
334+
msgctxt "accessibility"
335+
msgid "Go to VPN settings to change tunnel protocol"
336+
msgstr ""
337+
327338
#. Provided to accessibility tools such as screenreaders to describe
328339
#. the button which obscures the account number.
329340
msgctxt "accessibility"
@@ -900,6 +911,29 @@ msgctxt "in-app-notifications"
900911
msgid "%(duration)s. Buy more credit."
901912
msgstr ""
902913

914+
#. First part of notification subtitle when there are no openVPN servers available.
915+
#. Will be followed by a link to VPN settings.
916+
#. Available placeholders:
917+
#. %(openVpn)s - Will be replaced with OpenVPN
918+
msgctxt "in-app-notifications"
919+
msgid "%(openVpn)s support has ended. Please update the app or"
920+
msgstr ""
921+
922+
#. Notification title indicating that OpenVPN support is ending.
923+
#. Available placeholders:
924+
#. %(openVpn)s - Will be replaced with OPENVPN
925+
msgctxt "in-app-notifications"
926+
msgid "%(openVpn)s SUPPORT IS ENDING"
927+
msgstr ""
928+
929+
#. First part of notification subtitle when there are no openVPN servers
930+
#. matching current settings. Will be followed by a link to VPN settings.
931+
#. Available placeholders:
932+
#. %(openVpn)s - Will be replaced with OpenVPN
933+
msgctxt "in-app-notifications"
934+
msgid "%(openVpn)s support is ending. Switch location or"
935+
msgstr ""
936+
903937
msgctxt "in-app-notifications"
904938
msgid "ACCOUNT CREDIT EXPIRES SOON"
905939
msgstr ""
@@ -916,6 +950,14 @@ msgctxt "in-app-notifications"
916950
msgid "BLOCKING INTERNET"
917951
msgstr ""
918952

953+
#. Link following the first part of the notification subtitle.
954+
#. Will navigate the user to the VPN settings.
955+
#. Available placeholders:
956+
#. %(wireGuard)s - Will be replaced with WireGuard
957+
msgctxt "in-app-notifications"
958+
msgid "change tunnel protocol to %(wireGuard)s"
959+
msgstr ""
960+
919961
msgctxt "in-app-notifications"
920962
msgid "Click here to see what’s new."
921963
msgstr ""
@@ -937,10 +979,37 @@ msgctxt "in-app-notifications"
937979
msgid "NEW VERSION INSTALLED"
938980
msgstr ""
939981

982+
#. Notification title when there are no openVPN servers
983+
#. matching current settings.
984+
#. Available placeholders:
985+
#. %(openVpn)s - Will be replaced with OPENVPN
986+
msgctxt "in-app-notifications"
987+
msgid "NO %(openVpn)s SERVER AVAILABLE"
988+
msgstr ""
989+
990+
#. Notification title when there are no openVPN servers available.
991+
#. Available placeholders:
992+
#. %(openVpn)s - Will be replaced with OPENVPN
993+
msgctxt "in-app-notifications"
994+
msgid "NO %(openVpn)s SERVERS AVAILABLE"
995+
msgstr ""
996+
997+
#. Notification subtitle indicating that OpenVPN support is ending.
998+
#. Available placeholders:
999+
#. %(wireGuard)s - Will be replaced with WireGuard
1000+
msgctxt "in-app-notifications"
1001+
msgid "Please change tunnel protocol to %(wireGuard)s."
1002+
msgstr ""
1003+
9401004
msgctxt "in-app-notifications"
9411005
msgid "Please quit and restart the app."
9421006
msgstr ""
9431007

1008+
#. Link in notication to a blog post about OpenVPN support ending.
1009+
msgctxt "in-app-notifications"
1010+
msgid "Read more"
1011+
msgstr ""
1012+
9441013
msgctxt "in-app-notifications"
9451014
msgid "Send problem report"
9461015
msgstr ""
@@ -1946,6 +2015,13 @@ msgctxt "vpn-settings-view"
19462015
msgid "Attention: this setting cannot be used in combination with <b>%(customDnsFeatureName)s</b>"
19472016
msgstr ""
19482017

2018+
#. Footer text for tunnel protocol selector when OpenVPN is selected.
2019+
#. Available placeholders:
2020+
#. %(openvpn)s - Will be replaced with OpenVPN
2021+
msgctxt "vpn-settings-view"
2022+
msgid "Attention: We are removing support for %(openVpn)s."
2023+
msgstr ""
2024+
19492025
msgctxt "vpn-settings-view"
19502026
msgid "Auto-connect"
19512027
msgstr ""
@@ -2020,6 +2096,12 @@ msgctxt "vpn-settings-view"
20202096
msgid "Malware"
20212097
msgstr ""
20222098

2099+
#. Link in tunnel protocol selector footer to blog post
2100+
#. about OpenVPN support ending.
2101+
msgctxt "vpn-settings-view"
2102+
msgid "Read more"
2103+
msgstr ""
2104+
20232105
msgctxt "vpn-settings-view"
20242106
msgid "Server IP override"
20252107
msgstr ""

desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx

+18-17
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ import {
1616
} from '../../shared/notifications';
1717
import { useAppContext } from '../context';
1818
import useActions from '../lib/actionsHook';
19-
import { Colors } from '../lib/foundations';
2019
import { transitions, useHistory } from '../lib/history';
21-
import { formatHtml } from '../lib/html-formatter';
2220
import {
2321
NewDeviceNotificationProvider,
2422
NewVersionNotificationProvider,
23+
NoOpenVpnServerAvailableNotificationProvider,
24+
OpenVpnSupportEndingNotificationProvider,
2525
} from '../lib/notifications';
26+
import { useTunnelProtocol } from '../lib/relay-settings-hooks';
2627
import { RoutePath } from '../lib/routes';
2728
import accountActions from '../redux/account/actions';
2829
import { IReduxState, useSelector } from '../redux/store';
2930
import * as AppButton from './AppButton';
30-
import { InternalLink } from './InternalLink';
3131
import { ModalAlert, ModalAlertType, ModalMessage, ModalMessageList } from './Modal';
3232
import {
3333
NotificationActions,
@@ -36,10 +36,10 @@ import {
3636
NotificationContent,
3737
NotificationIndicator,
3838
NotificationOpenLinkAction,
39-
NotificationSubtitle,
4039
NotificationTitle,
4140
NotificationTroubleshootDialogAction,
4241
} from './NotificationBanner';
42+
import { NotificationSubtitle } from './NotificationSubtitle';
4343

4444
interface IProps {
4545
className?: string;
@@ -52,6 +52,10 @@ export default function NotificationArea(props: IProps) {
5252
const locale = useSelector((state: IReduxState) => state.userInterface.locale);
5353
const tunnelState = useSelector((state: IReduxState) => state.connection.status);
5454
const version = useSelector((state: IReduxState) => state.version);
55+
const tunnelProtocol = useTunnelProtocol();
56+
const reduxConnection = useSelector((state) => state.connection);
57+
const fullRelayList = useSelector((state) => state.settings.relayLocations);
58+
5559
const blockWhenDisconnected = useSelector(
5660
(state: IReduxState) => state.settings.blockWhenDisconnected,
5761
);
@@ -90,7 +94,11 @@ export default function NotificationArea(props: IProps) {
9094
blockWhenDisconnected,
9195
hasExcludedApps,
9296
}),
93-
97+
new NoOpenVpnServerAvailableNotificationProvider({
98+
tunnelProtocol,
99+
tunnelState: reduxConnection.status,
100+
relayLocations: fullRelayList,
101+
}),
94102
new ErrorNotificationProvider({
95103
tunnelState,
96104
hasExcludedApps,
@@ -120,6 +128,7 @@ export default function NotificationArea(props: IProps) {
120128
close,
121129
}),
122130
new UpdateAvailableNotificationProvider(version),
131+
new OpenVpnSupportEndingNotificationProvider({ tunnelProtocol }),
123132
);
124133

125134
const notificationProvider = notificationProviders.find((notification) =>
@@ -140,18 +149,10 @@ export default function NotificationArea(props: IProps) {
140149
<NotificationTitle data-testid="notificationTitle">
141150
{notification.title}
142151
</NotificationTitle>
143-
<NotificationSubtitle data-testid="notificationSubTitle">
144-
{notification.subtitleAction?.type === 'navigate-internal' ? (
145-
<InternalLink
146-
variant="labelTiny"
147-
color={Colors.white60}
148-
{...notification.subtitleAction.link}>
149-
{formatHtml(notification.subtitle ?? '')}
150-
</InternalLink>
151-
) : (
152-
formatHtml(notification.subtitle ?? '')
153-
)}
154-
</NotificationSubtitle>
152+
<NotificationSubtitle
153+
data-testid="notificationSubTitle"
154+
subtitle={notification.subtitle}
155+
/>
155156
</NotificationContent>
156157
{notification.action && (
157158
<NotificationActionWrapper

desktop/packages/mullvad-vpn/src/renderer/components/NotificationBanner.tsx

-12
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,6 @@ export const NotificationTitle = styled.span(tinyText, {
1515
color: Colors.white,
1616
});
1717

18-
export const NotificationSubtitleText = styled.span(tinyText, {
19-
color: Colors.white60,
20-
});
21-
22-
interface INotificationSubtitleProps {
23-
children?: React.ReactNode;
24-
}
25-
26-
export function NotificationSubtitle(props: INotificationSubtitleProps) {
27-
return React.Children.count(props.children) > 0 ? <NotificationSubtitleText {...props} /> : null;
28-
}
29-
3018
export const NotificationActionButton = styled(AppButton.SimpleButton)({
3119
flex: 1,
3220
justifyContent: 'center',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import { InAppNotificationSubtitle } from '../../shared/notifications';
5+
import { Icon, LabelTiny } from '../lib/components';
6+
import { Colors } from '../lib/foundations';
7+
import { formatHtml } from '../lib/html-formatter';
8+
import { ExternalLink } from './ExternalLink';
9+
import { InternalLink } from './InternalLink';
10+
11+
export type NotificationSubtitleProps = {
12+
subtitle?: string | InAppNotificationSubtitle[];
13+
};
14+
15+
const StyledIcon = styled(Icon)`
16+
display: inline-flex;
17+
vertical-align: middle;
18+
`;
19+
20+
const formatSubtitle = (subtitle: InAppNotificationSubtitle) => {
21+
const content = formatHtml(subtitle.content);
22+
if (subtitle.action) {
23+
switch (subtitle.action.type) {
24+
case 'navigate-internal':
25+
return (
26+
<InternalLink variant="labelTiny" {...subtitle.action.link}>
27+
{content}
28+
</InternalLink>
29+
);
30+
case 'navigate-external':
31+
return (
32+
<ExternalLink variant="labelTiny" {...subtitle.action.link}>
33+
{content}
34+
<StyledIcon icon="external" size="small" />
35+
</ExternalLink>
36+
);
37+
default:
38+
break;
39+
}
40+
}
41+
return content;
42+
};
43+
44+
export const NotificationSubtitle = ({ subtitle, ...props }: NotificationSubtitleProps) => {
45+
if (!subtitle) {
46+
return null;
47+
}
48+
49+
if (!Array.isArray(subtitle)) {
50+
return (
51+
<LabelTiny color={Colors.white60} {...props}>
52+
{formatHtml(subtitle)}
53+
</LabelTiny>
54+
);
55+
}
56+
57+
return (
58+
<LabelTiny color={Colors.white60} {...props}>
59+
{subtitle.map((subtitle, index, arr) => {
60+
const content = formatSubtitle(subtitle);
61+
62+
return (
63+
<React.Fragment key={subtitle.content}>
64+
{content}
65+
{index !== arr.length - 1 && ' '}
66+
</React.Fragment>
67+
);
68+
})}
69+
</LabelTiny>
70+
);
71+
};

desktop/packages/mullvad-vpn/src/renderer/components/VpnSettings.tsx

+33-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { useCallback, useMemo } from 'react';
22
import { sprintf } from 'sprintf-js';
33
import styled from 'styled-components';
44

5-
import { strings } from '../../shared/constants';
5+
import { strings, urls } from '../../shared/constants';
66
import { IDnsOptions, TunnelProtocol } from '../../shared/daemon-rpc-types';
77
import { messages } from '../../shared/gettext';
88
import log from '../../shared/logging';
99
import { useAppContext } from '../context';
10+
import { Flex, Icon } from '../lib/components';
1011
import { useRelaySettingsUpdater } from '../lib/constraint-updater';
1112
import { Colors, spacings } from '../lib/foundations';
1213
import { useHistory } from '../lib/history';
@@ -22,6 +23,7 @@ import { AriaDescription, AriaDetails, AriaInput, AriaInputGroup, AriaLabel } fr
2223
import * as Cell from './cell';
2324
import Selector, { SelectorItem } from './cell/Selector';
2425
import CustomDnsSettings from './CustomDnsSettings';
26+
import { ExternalLink } from './ExternalLink';
2527
import InfoButton from './InfoButton';
2628
import { BackAction } from './KeyboardNavigation';
2729
import { Layout, SettingsContainer, SettingsContent, SettingsGroup, SettingsStack } from './Layout';
@@ -725,7 +727,7 @@ function TunnelProtocolSetting() {
725727
value={tunnelProtocol}
726728
onSelect={setTunnelProtocol}
727729
/>
728-
{openVpnDisabled ? (
730+
{openVpnDisabled && (
729731
<Cell.CellFooter>
730732
<AriaDescription>
731733
<Cell.CellFooterText>
@@ -739,7 +741,35 @@ function TunnelProtocolSetting() {
739741
</Cell.CellFooterText>
740742
</AriaDescription>
741743
</Cell.CellFooter>
742-
) : null}
744+
)}
745+
{tunnelProtocol === 'openvpn' && (
746+
<Cell.CellFooter>
747+
<AriaDescription>
748+
<Cell.CellFooterText>
749+
{sprintf(
750+
// TRANSLATORS: Footer text for tunnel protocol selector when OpenVPN is selected.
751+
// TRANSLATORS: Available placeholders:
752+
// TRANSLATORS: %(openvpn)s - Will be replaced with OpenVPN
753+
messages.pgettext(
754+
'vpn-settings-view',
755+
'Attention: We are removing support for %(openVpn)s.',
756+
),
757+
{ openVpn: strings.openvpn },
758+
)}{' '}
759+
</Cell.CellFooterText>
760+
</AriaDescription>
761+
<ExternalLink variant="labelTiny" to={urls.removingOpenVpnBlog}>
762+
<Flex>
763+
{sprintf(
764+
// TRANSLATORS: Link in tunnel protocol selector footer to blog post
765+
// TRANSLATORS: about OpenVPN support ending.
766+
messages.pgettext('vpn-settings-view', 'Read more'),
767+
)}
768+
<Icon icon="external" size="small" />
769+
</Flex>
770+
</ExternalLink>
771+
</Cell.CellFooter>
772+
)}
743773
</AriaInputGroup>
744774
);
745775
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export * from './new-device';
22
export * from './new-version';
3+
export * from './open-vpn-support-ending';
4+
export * from './no-open-vpn-server-available';

0 commit comments

Comments
 (0)