Refresh UI on nodeKind changes, e.g. personal -> public (#5312)

* Poll details based on nodeKind

* Delay long polling when public/light

* Reload UI when nodeKind changed

* Fix tests (not using dispatch, reload instead)

* PR grumbles/cleanups
This commit is contained in:
Jaco Greeff 2017-04-20 17:31:15 +02:00 committed by GitHub
parent ee25249729
commit ba03ed4eea
4 changed files with 86 additions and 34 deletions

View File

@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BalancesProvider from './balances';
import { showSnackbar } from './snackbarActions';
import { DEFAULT_NETCHAIN } from './statusReducer';
export default class ChainMiddleware {
@ -24,20 +22,34 @@ export default class ChainMiddleware {
if (action.type === 'statusCollection') {
const { collection } = action;
if (collection && collection.netChain) {
const newChain = collection.netChain;
if (collection) {
const { nodeStatus } = store.getState();
const { netChain, nodeKind } = nodeStatus;
const newChain = collection.netChain;
const newNodeKind = collection.nodeKind;
let reloadChain = false;
let reloadType = false;
if (newChain !== nodeStatus.netChain && nodeStatus.netChain !== DEFAULT_NETCHAIN) {
store.dispatch(showSnackbar(`Switched to ${newChain}. The UI will reload now...`));
// force reload when chain has changed and is not initial value
if (newChain) {
const hasChainChanged = newChain !== netChain;
const isInitialChain = netChain === DEFAULT_NETCHAIN;
reloadChain = !isInitialChain && hasChainChanged;
}
// force reload when nodeKind (availability or capability) has changed
if (newNodeKind && nodeKind) {
const hasAvailabilityChanged = nodeKind.availability !== newNodeKind.availability;
const hasCapabilityChanged = nodeKind.capability !== newNodeKind.capability;
reloadType = hasAvailabilityChanged || hasCapabilityChanged;
}
if (reloadChain || reloadType) {
setTimeout(() => {
window.location.reload();
}, 0);
// Fetch the new balances without notifying the user of any change
BalancesProvider.get(store).fetchAllBalances({
changedNetwork: true
});
}
}
}

View File

@ -24,11 +24,22 @@ import { createWsApi } from '~/../test/e2e/ethapi';
let middleware;
let next;
let store;
let clock;
const api = createWsApi();
Contracts.create(api);
function stubGlobals () {
clock = sinon.useFakeTimers();
sinon.spy(window.location, 'reload');
}
function restoreGlobals () {
window.location.reload.restore();
clock.restore();
}
function createMiddleware (collection = {}) {
middleware = new ChainMiddleware().toMiddleware();
next = sinon.stub();
@ -46,10 +57,22 @@ function createMiddleware (collection = {}) {
}
function callMiddleware (action) {
return middleware(store)(next)(action);
const result = middleware(store)(next)(action);
clock.tick(100);
return result;
}
describe('reduxs/providers/ChainMiddleware', () => {
beforeEach(() => {
stubGlobals();
});
afterEach(() => {
restoreGlobals();
});
describe('next action', () => {
beforeEach(() => {
createMiddleware();
@ -69,25 +92,25 @@ describe('reduxs/providers/ChainMiddleware', () => {
});
describe('chain switching', () => {
it('does not dispatch when moving from the initial/unknown chain', () => {
it('does not reload when moving from the initial/unknown chain', () => {
createMiddleware();
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
expect(store.dispatch).not.to.have.been.called;
expect(window.location.reload).not.to.have.been.called;
});
it('does not dispatch when moving to the same chain', () => {
it('does not reload when moving to the same chain', () => {
createMiddleware({ netChain: 'homestead' });
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
expect(store.dispatch).not.to.have.been.called;
expect(window.location.reload).not.to.have.been.called;
});
it('does dispatch when moving between chains', () => {
it('does reload when moving between chains', () => {
createMiddleware({ netChain: 'homestead' });
callMiddleware({ type: 'statusCollection', collection: { netChain: 'ropsten' } });
expect(store.dispatch).to.have.been.called;
expect(window.location.reload).to.have.been.called;
});
});
});

View File

@ -156,7 +156,8 @@ export default class Status {
}
_pollTraceMode = () => {
return this._api.trace.block()
return this._api.trace
.block()
.then(blockTraces => {
// Assumes not in Trace Mode if no transactions
// in latest block...
@ -168,14 +169,12 @@ export default class Status {
getApiStatus = () => {
const { isConnected, isConnecting, needsToken, secureToken } = this._api;
const apiStatus = {
return {
isConnected,
isConnecting,
needsToken,
secureToken
};
return apiStatus;
}
_pollStatus = () => {
@ -194,7 +193,10 @@ export default class Status {
return Promise.resolve();
}
const statusPromises = [ this._api.eth.syncing(), this._api.parity.netPeers() ];
const statusPromises = [
this._api.eth.syncing(),
this._api.parity.netPeers()
];
return Promise
.all(statusPromises)
@ -225,7 +227,10 @@ export default class Status {
return Promise.resolve();
}
const nextTimeout = (timeout = 30000) => {
const { nodeKindFull } = this._store.getState().nodeStatus;
const defaultTimeout = (nodeKindFull === false ? 240 : 30) * 1000;
const nextTimeout = (timeout = defaultTimeout) => {
if (this._timeoutIds.longStatus) {
clearTimeout(this._timeoutIds.longStatus);
}
@ -233,24 +238,34 @@ export default class Status {
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
};
const statusPromises = [
this._api.parity.nodeKind(),
this._api.parity.netPeers(),
this._api.web3.clientVersion(),
this._api.net.version(),
this._api.parity.netChain()
];
if (nodeKindFull) {
statusPromises.push(this._upgradeStore.checkUpgrade());
}
return Promise
.all([
this._api.parity.netPeers(),
this._api.web3.clientVersion(),
this._api.net.version(),
this._api.parity.netChain(),
this._upgradeStore.checkUpgrade()
])
.then(([
netPeers, clientVersion, netVersion, netChain, upgradeStatus
]) => {
.all(statusPromises)
.then(([nodeKind, netPeers, clientVersion, netVersion, netChain]) => {
const isTest = [
'2', // morden
'3', // ropsten
'42' // kovan
].includes(netVersion);
const nodeKindFull = nodeKind &&
nodeKind.availability === 'personal' &&
nodeKind.capability === 'full';
const longStatus = {
nodeKind,
nodeKindFull,
netPeers,
clientVersion,
netChain,

View File

@ -31,6 +31,8 @@ const initialState = {
peers: []
},
netVersion: '0',
nodeKind: null,
nodeKindFull: null,
syncing: true,
isConnected: false,
isConnecting: false,