diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-01-26 09:19:06 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-01-26 09:19:06 +0100 |
| commit | 2c5163b9fa05e8b21ed92f6992e3a216e96817fe (patch) | |
| tree | 32f4f2e706e152626b31ca472e1e564f71340319 /gui/src/renderer | |
| parent | 2b055cc39c4eee4b8af8bb193143ddd4055b39ac (diff) | |
| parent | 5e9d51d61ecf3a7f8df10fcfc767213a108274c1 (diff) | |
| download | mullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.tar.xz mullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.zip | |
Merge branch 'sandbox-electron-renderer'
Diffstat (limited to 'gui/src/renderer')
| -rw-r--r-- | gui/src/renderer/app.tsx | 67 | ||||
| -rw-r--r-- | gui/src/renderer/components/AdvancedSettings.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/CustomScrollbars.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/Focus.tsx | 3 | ||||
| -rw-r--r-- | gui/src/renderer/components/HeaderBar.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/ImageView.tsx | 3 | ||||
| -rw-r--r-- | gui/src/renderer/components/NavigationBarStyles.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/PlatformWindow.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/Preferences.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/containers/SelectLanguagePage.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/context.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/index.html | 3 | ||||
| -rw-r--r-- | gui/src/renderer/lib/ipc-event-channel.ts | 5 | ||||
| -rw-r--r-- | gui/src/renderer/lib/load-translations.ts | 22 | ||||
| -rw-r--r-- | gui/src/renderer/lib/logging.ts | 3 | ||||
| -rw-r--r-- | gui/src/renderer/preload.ts | 4 | ||||
| -rw-r--r-- | gui/src/renderer/redux/settings/reducers.ts | 2 | ||||
| -rw-r--r-- | gui/src/renderer/redux/store.ts | 2 |
18 files changed, 87 insertions, 49 deletions
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index f63e03633a..9ff1459322 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -15,14 +15,15 @@ import configureStore from './redux/store'; import userInterfaceActions from './redux/userinterface/actions'; import versionActions from './redux/version/actions'; -import { ICurrentAppVersionInfo } from '../main'; -import { loadTranslations, messages, relayLocations } from '../shared/gettext'; -import { IGuiSettingsState, SYSTEM_PREFERRED_LOCALE_KEY } from '../shared/gui-settings-state'; -import { IpcRendererEventChannel, IRelayListPair } from '../shared/ipc-event-channel'; +import { ICurrentAppVersionInfo } from '../shared/ipc-types'; import { ILinuxSplitTunnelingApplication } from '../shared/application-types'; +import { messages, relayLocations } from '../shared/gettext'; +import { IGuiSettingsState, SYSTEM_PREFERRED_LOCALE_KEY } from '../shared/gui-settings-state'; import log, { ConsoleOutput } from '../shared/logging'; +import { IRelayListPair } from '../shared/ipc-schema'; import consumePromise from '../shared/promise'; import History from './lib/history'; +import { loadTranslations } from './lib/load-translations'; import { AccountToken, @@ -45,6 +46,8 @@ import { import { LogLevel } from '../shared/logging-types'; import IpcOutput from './lib/logging'; +const IpcRendererEventChannel = window.ipc; + interface IPreferredLocaleDescriptor { name: string; code: string; @@ -98,20 +101,6 @@ export default class AppRenderer { log.addOutput(new ConsoleOutput(LogLevel.debug)); log.addOutput(new IpcOutput(LogLevel.debug)); - IpcRendererEventChannel.locale.listen((locale) => { - // load translations for the new locale - this.loadTranslations(locale); - - // set current locale - this.setLocale(locale); - - // refresh the relay list pair with the new translations - this.propagateRelayListPairToRedux(); - - // refresh the location with the new translations - this.propagateLocationToRedux(); - }); - IpcRendererEventChannel.windowShape.listen((windowShapeParams) => { if (typeof windowShapeParams.arrowPosition === 'number') { this.reduxActions.userInterface.updateWindowArrowPosition(windowShapeParams.arrowPosition); @@ -186,9 +175,20 @@ export default class AppRenderer { // Request the initial state from the main process const initialState = IpcRendererEventChannel.state.get(); - // Load translations - this.loadTranslations(initialState.locale); + window.platform = initialState.platform; + window.runningInDevelopment = initialState.runningInDevelopment; + this.setLocale(initialState.locale); + loadTranslations( + messages, + initialState.translations.locale, + initialState.translations.messages, + ); + loadTranslations( + relayLocations, + initialState.translations.locale, + initialState.translations.relayLocations, + ); this.setAccountExpiry(initialState.accountData && initialState.accountData.expiry); this.handleAccountChange(undefined, initialState.settings.accountToken); @@ -464,8 +464,23 @@ export default class AppRenderer { ]; } - public setPreferredLocale(preferredLocale: string) { - IpcRendererEventChannel.guiSettings.setPreferredLocale(preferredLocale); + public async setPreferredLocale(preferredLocale: string): Promise<void> { + const translations = await IpcRendererEventChannel.guiSettings.setPreferredLocale( + preferredLocale, + ); + + // set current locale + this.setLocale(translations.locale); + + // load translations for new locale + loadTranslations(messages, translations.locale, translations.messages); + loadTranslations(relayLocations, translations.locale, translations.relayLocations); + + // refresh the relay list pair with the new translations + this.propagateRelayListPairToRedux(); + + // refresh the location with the new translations + this.propagateLocationToRedux(); } public getPreferredLocaleDisplayName(localeCode: string): string { @@ -479,12 +494,6 @@ export default class AppRenderer { this.loginTimer = global.setTimeout(() => this.history.resetWith('/connect'), 1000); } - private loadTranslations(locale: string) { - for (const catalogue of [messages, relayLocations]) { - loadTranslations(locale, catalogue); - } - } - private setLocale(locale: string) { this.locale = locale; this.reduxActions.userInterface.updateLocale(locale); @@ -576,7 +585,7 @@ export default class AppRenderer { } private async autoConnect() { - if (process.env.NODE_ENV === 'development') { + if (window.runningInDevelopment) { log.info('Skip autoconnect in development'); } else if (this.autoConnected) { log.info('Skip autoconnect because it was done before'); diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx index 6633e35746..7c97f0d844 100644 --- a/gui/src/renderer/components/AdvancedSettings.tsx +++ b/gui/src/renderer/components/AdvancedSettings.tsx @@ -429,7 +429,7 @@ export default class AdvancedSettings extends React.Component<IProps, IState> { <Cell.Icon height={12} width={7} source="icon-chevron" /> </Cell.CellButton> - {process.platform === 'linux' && ( + {window.platform === 'linux' && ( <Cell.CellButton onClick={this.props.onViewLinuxSplitTunneling}> <Cell.Label> {messages.pgettext('advanced-settings-view', 'Split tunneling')} diff --git a/gui/src/renderer/components/CustomScrollbars.tsx b/gui/src/renderer/components/CustomScrollbars.tsx index bc56ffcf3c..87c5b82dce 100644 --- a/gui/src/renderer/components/CustomScrollbars.tsx +++ b/gui/src/renderer/components/CustomScrollbars.tsx @@ -47,7 +47,7 @@ interface IScrollbarUpdateContext { export default class CustomScrollbars extends React.Component<IProps, IState> { public static defaultProps: IProps = { // auto-hide on macOS by default - autoHide: process.platform === 'darwin', + autoHide: window.platform === 'darwin', trackPadding: { x: 2, y: 2 }, }; diff --git a/gui/src/renderer/components/Focus.tsx b/gui/src/renderer/components/Focus.tsx index 6a2e9c7126..85c2c307e4 100644 --- a/gui/src/renderer/components/Focus.tsx +++ b/gui/src/renderer/components/Focus.tsx @@ -1,4 +1,3 @@ -import path from 'path'; import React, { useImperativeHandle, useState } from 'react'; import { useLocation } from 'react-router'; import { sprintf } from 'sprintf-js'; @@ -29,7 +28,7 @@ function Focus(props: IFocusProps, ref: React.Ref<IFocusHandle>) { ref, () => ({ resetFocus: () => { - const pageName = path.basename(location.pathname); + const pageName = location.pathname.slice(location.pathname.lastIndexOf('/') + 1); const titleElement = document.getElementsByTagName('h1')[0]; const titleContent = titleElement?.textContent ?? pageName; setTitle(titleContent); diff --git a/gui/src/renderer/components/HeaderBar.tsx b/gui/src/renderer/components/HeaderBar.tsx index 67b9622b21..bdf7d51924 100644 --- a/gui/src/renderer/components/HeaderBar.tsx +++ b/gui/src/renderer/components/HeaderBar.tsx @@ -28,7 +28,7 @@ interface IHeaderBarContainerProps { const HeaderBarContainer = styled.header({}, (props: IHeaderBarContainerProps) => ({ padding: '12px 16px', - paddingTop: process.platform === 'darwin' && !props.unpinnedWindow ? '24px' : '12px', + paddingTop: window.platform === 'darwin' && !props.unpinnedWindow ? '24px' : '12px', backgroundColor: headerBarStyleColorMap[props.barStyle ?? HeaderBarStyle.default], })); diff --git a/gui/src/renderer/components/ImageView.tsx b/gui/src/renderer/components/ImageView.tsx index fd6588b1fb..3be04159a2 100644 --- a/gui/src/renderer/components/ImageView.tsx +++ b/gui/src/renderer/components/ImageView.tsx @@ -1,4 +1,3 @@ -import path from 'path'; import React, { useMemo } from 'react'; import styled from 'styled-components'; @@ -40,7 +39,7 @@ const ImageMask = styled.div((props: IImageMaskProps) => { const HiddenImage = styled.img({ visibility: 'hidden' }); export default function ImageView(props: IImageViewProps) { - const url = path.isAbsolute(props.source) + const url = props.source.startsWith('data:') ? props.source : `../../assets/images/${props.source}.svg`; diff --git a/gui/src/renderer/components/NavigationBarStyles.tsx b/gui/src/renderer/components/NavigationBarStyles.tsx index 98c5184ea3..a82256b077 100644 --- a/gui/src/renderer/components/NavigationBarStyles.tsx +++ b/gui/src/renderer/components/NavigationBarStyles.tsx @@ -20,7 +20,7 @@ export const StyledNavigationItems = styled.div({ export const StyledNavigationBar = styled.nav((props: { unpinnedWindow: boolean }) => ({ flex: 0, padding: '12px', - paddingTop: process.platform === 'darwin' && !props.unpinnedWindow ? '24px' : '12px', + paddingTop: window.platform === 'darwin' && !props.unpinnedWindow ? '24px' : '12px', })); export const StyledNavigationBarWrapper = styled.div({ diff --git a/gui/src/renderer/components/PlatformWindow.tsx b/gui/src/renderer/components/PlatformWindow.tsx index 633b7aee95..83aa7b3f7f 100644 --- a/gui/src/renderer/components/PlatformWindow.tsx +++ b/gui/src/renderer/components/PlatformWindow.tsx @@ -10,7 +10,7 @@ interface IPlatformWindowProps { export default styled.div({}, (props: IPlatformWindowProps) => { let mask: string | undefined; - if (process.platform === 'darwin' && !props.unpinnedWindow) { + if (window.platform === 'darwin' && !props.unpinnedWindow) { const arrowPositionCss = props.arrowPosition !== undefined ? `${props.arrowPosition - ARROW_WIDTH * 0.5}px` : '50%'; diff --git a/gui/src/renderer/components/Preferences.tsx b/gui/src/renderer/components/Preferences.tsx index ab2b423686..d47a7315c6 100644 --- a/gui/src/renderer/components/Preferences.tsx +++ b/gui/src/renderer/components/Preferences.tsx @@ -179,8 +179,8 @@ export default class Preferences extends React.Component<IProps> { </Cell.Footer> </AriaInputGroup> - {(process.platform === 'win32' || - (process.platform === 'darwin' && process.env.NODE_ENV === 'development')) && ( + {(window.platform === 'win32' || + (window.platform === 'darwin' && window.runningInDevelopment)) && ( <AriaInputGroup> <Cell.Container> <AriaLabel> diff --git a/gui/src/renderer/containers/SelectLanguagePage.tsx b/gui/src/renderer/containers/SelectLanguagePage.tsx index eb052fb8a6..5c073c22e1 100644 --- a/gui/src/renderer/containers/SelectLanguagePage.tsx +++ b/gui/src/renderer/containers/SelectLanguagePage.tsx @@ -11,8 +11,8 @@ const mapStateToProps = (state: IReduxState) => ({ const mapDispatchToProps = (_dispatch: ReduxDispatch, props: RouteComponentProps & IAppContext) => { return { preferredLocalesList: props.app.getPreferredLocaleList(), - setPreferredLocale(locale: string) { - props.app.setPreferredLocale(locale); + async setPreferredLocale(locale: string) { + await props.app.setPreferredLocale(locale); props.history.goBack(); }, onClose() { diff --git a/gui/src/renderer/context.tsx b/gui/src/renderer/context.tsx index 113a29fe71..d4b20daeb1 100644 --- a/gui/src/renderer/context.tsx +++ b/gui/src/renderer/context.tsx @@ -6,7 +6,7 @@ export interface IAppContext { } export const AppContext = React.createContext<IAppContext | undefined>(undefined); -if (process.env.NODE_ENV === 'development') { +if (window.runningInDevelopment) { AppContext.displayName = 'AppContext'; } @@ -34,7 +34,7 @@ export default function withAppContext<Props>(BaseComponent: React.ComponentType ); }; - if (process.env.NODE_ENV === 'development') { + if (window.runningInDevelopment) { wrappedComponent.displayName = 'withAppContext(' + (BaseComponent.displayName || BaseComponent.name) + ')'; } diff --git a/gui/src/renderer/index.html b/gui/src/renderer/index.html index 3f2da3d633..043955b3c5 100644 --- a/gui/src/renderer/index.html +++ b/gui/src/renderer/index.html @@ -4,10 +4,11 @@ <title>Mullvad VPN</title> <link rel="stylesheet" href="../../assets/css/style.css" /> <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'"> + <meta charset="UTF-8"> </head> <body> <div id="app"></div> <script>var exports = {};</script> - <script src="./index.js"></script> + <script src="./bundle.js"></script> </body> </html> diff --git a/gui/src/renderer/lib/ipc-event-channel.ts b/gui/src/renderer/lib/ipc-event-channel.ts new file mode 100644 index 0000000000..bcb816e918 --- /dev/null +++ b/gui/src/renderer/lib/ipc-event-channel.ts @@ -0,0 +1,5 @@ +import { ipcRenderer } from 'electron'; +import { createIpcRenderer } from '../../shared/ipc-helpers'; +import { ipcSchema } from '../../shared/ipc-schema'; + +export const IpcRendererEventChannel = createIpcRenderer(ipcSchema, ipcRenderer); diff --git a/gui/src/renderer/lib/load-translations.ts b/gui/src/renderer/lib/load-translations.ts new file mode 100644 index 0000000000..43a483de25 --- /dev/null +++ b/gui/src/renderer/lib/load-translations.ts @@ -0,0 +1,22 @@ +import { GetTextTranslations } from 'gettext-parser'; +import Gettext from 'node-gettext'; +import log from '../../shared/logging'; + +const SOURCE_LANGUAGE = 'en'; + +export function loadTranslations( + catalogue: Gettext, + locale: string, + translations?: GetTextTranslations, +) { + if (translations) { + catalogue.addTranslations(locale, catalogue.domain, translations); + catalogue.setLocale(locale); + log.info(`Loaded translations ${locale}/${catalogue.domain}`); + } else { + // Reset the locale to source language if we couldn't load the catalogue for the requested locale + // Add empty translations to suppress some of the warnings produces by node-gettext + catalogue.addTranslations(SOURCE_LANGUAGE, catalogue.domain, {}); + catalogue.setLocale(SOURCE_LANGUAGE); + } +} diff --git a/gui/src/renderer/lib/logging.ts b/gui/src/renderer/lib/logging.ts index 433ba20f8f..7c8dc9e542 100644 --- a/gui/src/renderer/lib/logging.ts +++ b/gui/src/renderer/lib/logging.ts @@ -1,10 +1,9 @@ -import { IpcRendererEventChannel } from '../../shared/ipc-event-channel'; import { ILogOutput, LogLevel } from '../../shared/logging-types'; export default class IpcOutput implements ILogOutput { constructor(public level: LogLevel) {} public write(level: LogLevel, message: string) { - IpcRendererEventChannel.logging.log({ level: level, message }); + window.ipc.logging.log({ level: level, message }); } } diff --git a/gui/src/renderer/preload.ts b/gui/src/renderer/preload.ts new file mode 100644 index 0000000000..5c44b71eeb --- /dev/null +++ b/gui/src/renderer/preload.ts @@ -0,0 +1,4 @@ +import { contextBridge } from 'electron'; +import { IpcRendererEventChannel } from './lib/ipc-event-channel'; + +contextBridge.exposeInMainWorld('ipc', IpcRendererEventChannel); diff --git a/gui/src/renderer/redux/settings/reducers.ts b/gui/src/renderer/redux/settings/reducers.ts index 59b4c32b46..592caab687 100644 --- a/gui/src/renderer/redux/settings/reducers.ts +++ b/gui/src/renderer/redux/settings/reducers.ts @@ -148,7 +148,7 @@ const initialState: ISettingsReduxState = { autoConnect: true, monochromaticIcon: false, startMinimized: false, - unpinnedWindow: process.platform !== 'win32' && process.platform !== 'darwin', + unpinnedWindow: window.platform !== 'win32' && window.platform !== 'darwin', }, relaySettings: { normal: { diff --git a/gui/src/renderer/redux/store.ts b/gui/src/renderer/redux/store.ts index 49f864d18b..92d85e4dbe 100644 --- a/gui/src/renderer/redux/store.ts +++ b/gui/src/renderer/redux/store.ts @@ -54,7 +54,7 @@ export default function configureStore(initialState?: IReduxState) { const composeEnhancers: typeof compose = (() => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const reduxCompose = window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; - if (process.env.NODE_ENV === 'development' && reduxCompose) { + if (window.runningInDevelopment && reduxCompose) { return reduxCompose({ actionCreators }); } return compose; |
