fix: an open popup follows a network switch the background saves (closes #650)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

When the background saves a network switch after the user approves a
site's request, or another popup page saves one, an open popup now
notices the stored record change and takes the new network from it,
holding the lock, inside a save. It then leaves the page as a switch in
Settings does: the stack is cut, every screen counts as not yet
rendered, and the screen on top is drawn again. The cut and the redraw
are now two functions in the Settings view that both paths call. A
record already on the popup's network, such as its own Settings switch,
changes nothing. The popup never switches the network itself.

Model: opus-5-5
This commit is contained in:
2026-10-20 21:46:36 +00:00
parent e517219038
commit 59d8f478ae
15 changed files with 420 additions and 61 deletions
+56 -27
View File
@@ -38,6 +38,8 @@ const {
const { notify, sendMessage } = require("../../shared/browserApi");
let ctx;
let versionClickCount = 0;
let versionClickTimer = null;
@@ -243,7 +245,51 @@ async function renderSiteLists() {
);
}
function init(ctx) {
// A network switch, made by the user here or saved by the background once the
// user approved a site's request (src/popup/index.js), leaves every screen on
// the page showing the previous network. These two leave the page as README's
// Screen Map describes, the first before the switch is saved, so that save
// keeps the cut for a popup closed straight after, the second once `state`
// holds the new network.
//
// The stack is cut at the first screen that cannot be rendered from saved
// state, such as Send or AddToken, and at AddressToken unless it shows the
// native token: any other token there was picked on the previous network, so
// it is no longer selected either. Without a wallet the stack starts at
// Welcome, which that cut would drop, and Welcome shows nothing from a network.
function cutViewStack() {
if (!state.hasWallet) return;
if (state.selectedToken !== "ETH") {
const tokenView = state.viewStack.indexOf("address-token");
if (tokenView !== -1) {
state.viewStack = state.viewStack.slice(0, tokenView);
}
state.selectedToken = null;
}
state.viewStack = restorableStack(state.viewStack, state.currentView);
}
// Every screen counts as not yet rendered, so "Back" renders the one it lands
// on for the new network. Settings on top is brought up to date in place;
// any other screen is drawn again as a reopened popup draws it, which is Home
// for one that cannot be rendered from saved state. Without a wallet any other
// screen is Welcome or AddWallet, which show nothing from a network.
function showNewNetwork() {
resetRenderedViews();
if (state.currentView === "settings") {
markViewRendered("settings");
$("settings-network").value = state.networkId;
$("settings-rpc").value = state.rpcUrl;
$("settings-blockscout").value = state.blockscoutUrl;
renderTrackedTokens();
} else if (state.hasWallet) {
ctx.restoreView();
}
updateDebugBanner(state.currentView);
}
function init(_ctx) {
ctx = _ctx;
deleteWallet.init(ctx);
showPhrase.init();
@@ -321,35 +367,12 @@ function init(ctx) {
networkSelect.addEventListener("change", async () => {
const newId = networkSelect.value;
if (newId === state.networkId) return;
// The screens beneath Settings show the previous network, so Back
// finds them as it does in a reopened popup: each is rendered again
// when Back lands on it, and the stack is cut at the first one that
// cannot be rendered from saved state, such as Send or AddToken. It
// is cut at AddressToken too, unless that shows the native token: any
// other token there was picked on the previous network. Without a
// wallet the stack starts at Welcome, which that cut would drop, and
// Welcome shows nothing from a network. The cut comes before the
// switch so that the switch's save keeps it for a popup closed
// straight after.
if (state.hasWallet) {
const tokenView = state.viewStack.indexOf("address-token");
if (tokenView !== -1 && state.selectedToken !== "ETH") {
state.viewStack = state.viewStack.slice(0, tokenView);
}
state.viewStack = restorableStack(state.viewStack, "settings");
}
cutViewStack();
const net = await onChainSwitch(newId);
// Open pages are told by the background, as after a site's approved
// switch request.
notify({ type: "AUTISTMASK_NETWORK_CHANGED", chainId: net.chainId });
resetRenderedViews();
// Settings itself, and the testnet banner above it, are brought up
// to date for the new network here.
markViewRendered("settings");
$("settings-rpc").value = state.rpcUrl;
$("settings-blockscout").value = state.blockscoutUrl;
renderTrackedTokens();
updateDebugBanner(state.currentView);
showNewNetwork();
showFlash("Switched to " + net.name + ".");
});
@@ -484,4 +507,10 @@ function init(ctx) {
});
}
module.exports = { init, show, renderSiteLists };
module.exports = {
init,
show,
renderSiteLists,
cutViewStack,
showNewNetwork,
};