summaryrefslogtreecommitdiffhomepage
path: root/gui
diff options
context:
space:
mode:
Diffstat (limited to 'gui')
-rw-r--r--gui/package-lock.json44
-rw-r--r--gui/package.json2
-rw-r--r--gui/src/renderer/app.tsx8
-rw-r--r--gui/src/renderer/lib/history.ts112
-rw-r--r--gui/src/renderer/redux/store.ts2
5 files changed, 121 insertions, 47 deletions
diff --git a/gui/package-lock.json b/gui/package-lock.json
index 249ef3ddda..9507dcc279 100644
--- a/gui/package-lock.json
+++ b/gui/package-lock.json
@@ -604,9 +604,9 @@
"dev": true
},
"@types/history": {
- "version": "4.7.5",
- "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.5.tgz",
- "integrity": "sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==",
+ "version": "4.7.8",
+ "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.8.tgz",
+ "integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==",
"dev": true
},
"@types/hoist-non-react-statics": {
@@ -6872,18 +6872,6 @@
"integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==",
"dev": true
},
- "history": {
- "version": "4.7.2",
- "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
- "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
- "requires": {
- "invariant": "^2.2.1",
- "loose-envify": "^1.2.0",
- "resolve-pathname": "^2.2.0",
- "value-equal": "^0.4.0",
- "warning": "^3.0.0"
- }
- },
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -7269,14 +7257,6 @@
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
"dev": true
},
- "invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@@ -10616,11 +10596,6 @@
"value-or-function": "^3.0.0"
}
},
- "resolve-pathname": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
- "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
- },
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -12869,11 +12844,6 @@
"spdx-expression-parse": "^3.0.0"
}
},
- "value-equal": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
- "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
- },
"value-or-function": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
@@ -12963,14 +12933,6 @@
}
}
},
- "warning": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
- "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
"warning-symbol": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz",
diff --git a/gui/package.json b/gui/package.json
index 22593150b3..734b3f8a66 100644
--- a/gui/package.json
+++ b/gui/package.json
@@ -19,7 +19,6 @@
"electron-log": "^4.1.1",
"gettext-parser": "^4.0.3",
"google-protobuf": "^4.0.0-rc.2",
- "history": "^4.6.1",
"linux-app-list": "^1.0.1",
"mkdirp": "^1.0.3",
"moment": "^2.24.0",
@@ -47,6 +46,7 @@
"@types/enzyme-adapter-react-16": "^1.0.3",
"@types/gettext-parser": "^4.0.0",
"@types/google-protobuf": "^3.7.2",
+ "@types/history": "^4.7.8",
"@types/mkdirp": "^1.0.0",
"@types/mocha": "^5.2.6",
"@types/node": "^10.12.3",
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index b7c9b1a187..e76eec0453 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -5,7 +5,6 @@ import {
} from 'connected-react-router';
import { ipcRenderer, shell, webFrame } from 'electron';
import log from 'electron-log';
-import { createMemoryHistory } from 'history';
import * as React from 'react';
import { Provider } from 'react-redux';
import { bindActionCreators } from 'redux';
@@ -29,6 +28,7 @@ import { IpcRendererEventChannel, IRelayListPair } from '../shared/ipc-event-cha
import ISplitTunnelingApplication from '../shared/linux-split-tunneling-application';
import { getRendererLogFile, setupLogging } from '../shared/logging';
import consumePromise from '../shared/promise';
+import History from './lib/history';
import {
AccountToken,
@@ -76,8 +76,8 @@ const SUPPORTED_LOCALE_LIST = [
];
export default class AppRenderer {
- private memoryHistory = createMemoryHistory();
- private reduxStore = configureStore(this.memoryHistory);
+ private history = new History('/');
+ private reduxStore = configureStore(this.history);
private reduxActions = {
account: bindActionCreators(accountActions, this.reduxStore.dispatch),
connection: bindActionCreators(connectionActions, this.reduxStore.dispatch),
@@ -229,7 +229,7 @@ export default class AppRenderer {
return (
<AppContext.Provider value={{ app: this }}>
<Provider store={this.reduxStore}>
- <ConnectedRouter history={this.memoryHistory}>
+ <ConnectedRouter history={this.history}>
<ErrorBoundary>
<AppRoutes />
</ErrorBoundary>
diff --git a/gui/src/renderer/lib/history.ts b/gui/src/renderer/lib/history.ts
new file mode 100644
index 0000000000..b726e72bbb
--- /dev/null
+++ b/gui/src/renderer/lib/history.ts
@@ -0,0 +1,112 @@
+import { Location, Action, LocationListener, LocationDescriptor } from 'history';
+
+// It currently isn't possible to implement this correctly with support for a generic state. State
+// can be added as a generic type (<S = unknown>) after this issue has been resolved:
+// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/49060
+type S = unknown;
+export default class History {
+ private listeners: LocationListener<S>[] = [];
+ private entries: Location<S>[];
+ private index = 0;
+ private lastAction: Action = 'POP';
+
+ public constructor(location: string | Location<S>, state?: S) {
+ this.entries = [this.createLocation(location, state)];
+ }
+
+ public get location(): Location<S> {
+ return this.entries[this.index];
+ }
+
+ public get length(): number {
+ return this.entries.length;
+ }
+
+ public get action(): Action {
+ return this.lastAction;
+ }
+
+ public push = (nextLocation: LocationDescriptor<S>, nextState?: S) => {
+ const location = this.createLocation(nextLocation, nextState);
+ this.lastAction = 'PUSH';
+ this.index += 1;
+ this.entries.splice(this.index, this.entries.length - this.index, location);
+ this.notify();
+ };
+
+ public replace = (nextLocation: LocationDescriptor<S>, nextState?: S) => {
+ this.entries[this.index] = this.createLocation(nextLocation, nextState);
+ this.lastAction = 'REPLACE';
+ this.notify();
+ };
+
+ public go = (n: number) => {
+ if (this.canGo(n)) {
+ this.index += n;
+ this.lastAction = 'POP';
+ this.notify();
+ }
+ };
+
+ public goBack = () => this.go(-1);
+ public goForward = () => this.go(1);
+
+ public reset = () => {
+ this.lastAction = 'POP';
+ this.index = 0;
+ this.notify();
+ };
+
+ public resetWith = (nextLocation: LocationDescriptor<S>, nextState?: S) => {
+ this.entries = [this.createLocation(nextLocation, nextState)];
+ this.lastAction = 'REPLACE';
+ this.index = 0;
+ this.notify();
+ };
+
+ public canGo(n: number) {
+ const nextIndex = this.index + n;
+ return nextIndex >= 0 && nextIndex < this.entries.length;
+ }
+
+ public listen(callback: LocationListener<S>) {
+ this.listeners.push(callback);
+ return () => (this.listeners = this.listeners.filter((listener) => listener !== callback));
+ }
+
+ public block(): () => void {
+ throw Error('Not implemented');
+ }
+
+ public createHref(): string {
+ throw Error('Not implemented');
+ }
+
+ private notify() {
+ this.listeners.forEach((listener) => listener(this.location, this.action));
+ }
+
+ private createLocation(location: LocationDescriptor<S>, state?: S): Location<S> {
+ if (typeof location === 'object') {
+ return {
+ pathname: location.pathname ?? this.location.pathname,
+ search: location.search ?? '',
+ hash: location.hash ?? '',
+ state: location.state,
+ key: location.key ?? this.getRandomKey(),
+ };
+ } else {
+ return {
+ pathname: location,
+ search: '',
+ hash: '',
+ state,
+ key: this.getRandomKey(),
+ };
+ }
+ }
+
+ private getRandomKey() {
+ return Math.random().toString(36).substr(8);
+ }
+}
diff --git a/gui/src/renderer/redux/store.ts b/gui/src/renderer/redux/store.ts
index bedaddf1bd..43ebc312ef 100644
--- a/gui/src/renderer/redux/store.ts
+++ b/gui/src/renderer/redux/store.ts
@@ -14,7 +14,7 @@ import userInterfaceReducer, { IUserInterfaceReduxState } from './userinterface/
import versionActions, { VersionAction } from './version/actions';
import versionReducer, { IVersionReduxState } from './version/reducers';
-import { History } from 'history';
+import History from '../lib/history';
export interface IReduxState {
account: IAccountReduxState;