Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iss 279 - When selecting a new Node under Settings -> Access, don't hard reload the browser #380

Merged
merged 9 commits into from
Sep 12, 2017
25 changes: 13 additions & 12 deletions app/components/Settings/AccessSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Translate from "react-translate-component";
import counterpart from "counterpart";
import SettingsActions from "actions/SettingsActions";
import { settingsAPIs } from "../../api/apiConfig";
import willTransitionTo from "../../routerTransition";
import { withRouter } from "react-router/es";

import ls from "common/localStorage";
const STORAGE_KEY = "__graphene__";
Expand All @@ -28,14 +30,11 @@ class ApiNode extends React.Component {
}

activate(){
SettingsActions.changeSetting({setting: "apiServer", value: this.props.url });
setTimeout(this._onReloadClick, 250);

if (window.electron) {
window.location.hash = "";
window.remote.getCurrentWindow().reload();
}
else window.location.href = __BASE_URL__;
let action = SettingsActions.changeSetting({setting: "apiServer", value: this.props.url });

setTimeout(function(){
willTransitionTo(this.props.router, this.props.router.replace, ()=>{}, false);
}.bind(this), 50);
}

remove(url, name, e){
Expand Down Expand Up @@ -72,12 +71,12 @@ class ApiNode extends React.Component {

{(!allowActivation && !allowRemoval && !automatic) && Status}

{allowActivation && !automatic && !state.hovered && Status}
{allowActivation && !automatic && (up ? !state.hovered : (allowRemoval ? !state.hovered : true) ) && Status}

{(allowActivation || allowRemoval) && state.hovered &&
<div style={{position: "absolute", right: "1em", top: "1.2em"}}>
{allowRemoval && <div className="button" onClick={this.remove.bind(this, url, name)}><Translate id="remove" content="settings.remove" /></div>}
{allowActivation && <div className="button" onClick={this.activate.bind(this)}><Translate content="settings.activate" /></div>}
{ allowRemoval && <div className="button" onClick={this.remove.bind(this, url, name)}><Translate id="remove" content="settings.remove" /></div>}
{(automatic ? true : up) && allowActivation && <div className="button" onClick={this.activate.bind(this)}><Translate content="settings.activate" /></div>}
</div>
}
</div>
Expand All @@ -94,6 +93,8 @@ ApiNode.defaultProps = {
allowRemoval: false
}

const ApiNodeWithRouter = withRouter(ApiNode);

class AccessSettings extends React.Component {
constructor(props){
super(props);
Expand Down Expand Up @@ -152,7 +153,7 @@ class AccessSettings extends React.Component {

let allowRemoval = (!automatic && !this.isDefaultNode[node.url]) ? true : false;

return <ApiNode {...node} automatic={automatic} allowActivation={allowActivation} allowRemoval={allowActivation && allowRemoval} key={node.url} name={name} displayUrl={displayUrl} triggerModal={props.triggerModal} />
return <ApiNodeWithRouter {...node} automatic={automatic} allowActivation={allowActivation} allowRemoval={allowActivation && allowRemoval} key={node.url} name={name} displayUrl={displayUrl} triggerModal={props.triggerModal} />
}

render(){
Expand Down
125 changes: 67 additions & 58 deletions app/routerTransition.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const filterAndSortURLs = (count, latencies) => {
return urls;
};

const willTransitionTo = (nextState, replaceState, callback) => {
const willTransitionTo = (nextState, replaceState, callback, appInit=true) => { //appInit is true when node is manually selected in access settings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this say that appInit is false when selecting nodes in the settings?

Copy link
Contributor Author

@calvinfroedge calvinfroedge Sep 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because appInit (which includes fallbacks) should only happen when it's not user choice. I'm using this to differentiate between user picking a server and server being chosen when the app is loaded.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, so when a user picks a server appInit is false, but on first load of the app it is true, which is the opposite of what the comment says. You are calling it with false on line 36

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lolz. Yea, just need to fix the comment.

if (connect) ss.set("latencyChecks", latencyChecks + 1); // Every 15 connect attempts we refresh the api latency list
if (latencyChecks >= 15) {
apiLatenciesCount = 0;
Expand All @@ -62,26 +62,30 @@ const willTransitionTo = (nextState, replaceState, callback) => {
if (!connectionString) connectionString = urls[0].url;
if (connectionString.indexOf("fake.automatic-selection") !== -1) connectionString = urls[0];

if (!connectionManager) connectionManager = new Manager({url: connectionString, urls});
if (nextState.location.pathname === "/init-error") {
return Apis.reset(connectionString, true).init_promise
.then(() => {
var db;
try {
db = iDB.init_instance(window.openDatabase ? (shimIndexedDB || indexedDB) : indexedDB).init_promise;
} catch(err) {
console.log("db init error:", err);
}
return Promise.all([db, SettingsStore.init()]).then(() => {
return callback();
}).catch((err) => {
console.log("err:", err);
return callback();
});
var onReset = () => {
var db;
try {
db = iDB.init_instance(window.openDatabase ? (shimIndexedDB || indexedDB) : indexedDB).init_promise;
} catch(err) {
console.log("db init error:", err);
}
return Promise.all([db, SettingsStore.init()]).then(() => {
return callback();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reset callback needs to include the promises loading the WalletDb and PrivateKeyActions data, (PrivateKeyActions.loadDbData() and WalletDb.loadDbData()), since the wallet that is loaded depends on the chain id of the websocket API you're connected to. If you switch from the mainnet to the testnet you need to load the correct wallet and private keys. I'm not sure how well those methods play with on the fly switching

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, can refactor this so the logic is included for both.

}).catch((err) => {
console.log("err:", err);
return callback();
});
}

var onResetError = (err) => {
console.log("err:", err);
return callback();
}

connectionManager = new Manager({url: connectionString, urls});
if (nextState.location.pathname === "/init-error") {
return Apis.reset(connectionString, true).init_promise
.then(onReset).catch(onResetError);

}
let connectionCheckPromise = !apiLatenciesCount ? connectionManager.checkConnections() : null;
Expand All @@ -97,51 +101,56 @@ const willTransitionTo = (nextState, replaceState, callback) => {
}
let latencies = ss.get("apiLatencies", {});
let connectionStart = new Date().getTime();
connectionManager.connectWithFallback(connect).then(() => {
/* Update the latencies object and current active node */
latencies[connectionManager.url] = new Date().getTime() - connectionStart;
SettingsActions.changeSetting({setting: "apiServer", value: connectionManager.url});
SettingsActions.updateLatencies(latencies);

var db;
try {
db = iDB.init_instance(window.openDatabase ? (shimIndexedDB || indexedDB) : indexedDB).init_promise;
} catch(err) {
console.log("db init error:", err);
}
return Promise.all([db, SettingsStore.init()]).then(() => {
return Promise.all([
PrivateKeyActions.loadDbData().then(()=> AccountRefsStore.loadDbData()),
WalletDb.loadDbData().then(() => {
// if (!WalletDb.getWallet() && nextState.location.pathname === "/") {
// replaceState("/dashboard");
// }
if (nextState.location.pathname.indexOf("/auth/") === 0) {
replaceState("/dashboard");
}
}).catch((error) => {
console.error("----- WalletDb.willTransitionTo error ----->", error);
replaceState("/init-error");
}),
WalletManagerStore.init()
]).then(()=> {
ss.set("activeNode", connectionManager.url);
callback();
if(appInit){
connectionManager.connectWithFallback(connect).then(() => {
/* Update the latencies object and current active node */
latencies[connectionManager.url] = new Date().getTime() - connectionStart;
SettingsActions.changeSetting({setting: "apiServer", value: connectionManager.url});
SettingsActions.updateLatencies(latencies);

var db;
try {
db = iDB.init_instance(window.openDatabase ? (shimIndexedDB || indexedDB) : indexedDB).init_promise;
} catch(err) {
console.log("db init error:", err);
}
return Promise.all([db, SettingsStore.init()]).then(() => {
return Promise.all([
PrivateKeyActions.loadDbData().then(()=> AccountRefsStore.loadDbData()),
WalletDb.loadDbData().then(() => {
// if (!WalletDb.getWallet() && nextState.location.pathname === "/") {
// replaceState("/dashboard");
// }
if (nextState.location.pathname.indexOf("/auth/") === 0) {
replaceState("/dashboard");
}
}).catch((error) => {
console.error("----- WalletDb.willTransitionTo error ----->", error);
replaceState("/init-error");
}),
WalletManagerStore.init()
]).then(()=> {
ss.set("activeNode", connectionManager.url);
callback();
});
});
});
}).catch( error => {
console.error("----- App.willTransitionTo error ----->", error, (new Error).stack);
if(error.name === "InvalidStateError") {
if (__ELECTRON__) {
replaceState("/dashboard");
}).catch( error => {
console.error("----- App.willTransitionTo error ----->", error, (new Error).stack);
if(error.name === "InvalidStateError") {
if (__ELECTRON__) {
replaceState("/dashboard");
} else {
alert("Can't access local storage.\nPlease make sure your browser is not in private/incognito mode.");
}
} else {
alert("Can't access local storage.\nPlease make sure your browser is not in private/incognito mode.");
replaceState("/init-error");
callback();
}
} else {
replaceState("/init-error");
callback();
}
});
});
} else {
Apis.reset(connectionManager.url, true).init_promise.then(onReset).catch(onResetError);
}

/* Only try initialize the API with connect = true on the first onEnter */
connect = false;
Expand Down