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:
parent
ee25249729
commit
ba03ed4eea
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -31,6 +31,8 @@ const initialState = {
|
||||
peers: []
|
||||
},
|
||||
netVersion: '0',
|
||||
nodeKind: null,
|
||||
nodeKindFull: null,
|
||||
syncing: true,
|
||||
isConnected: false,
|
||||
isConnecting: false,
|
||||
|
Loading…
Reference in New Issue
Block a user