diff --git a/internal/gui/assets/app.js b/internal/gui/assets/app.js index 75036f3a..8a0a3b11 100644 --- a/internal/gui/assets/app.js +++ b/internal/gui/assets/app.js @@ -585,8 +585,9 @@ function toggleProfile(chip, p) { } // closeProfileDetail closes the details shown, if any: false if none were. +// Details on the page close whether or not profileOpen still names them. function closeProfileDetail() { - if (!profileOpen) return false; + if (!profileOpen && !$("#profiles > .prof-detail")) return false; profileOpen = null; $("#profiles > .prof-detail")?.remove(); $(".profiles").classList.remove("detailed"); @@ -2511,7 +2512,10 @@ async function profileAction(action, name, update) { state = data; renderAgents(); if (action === "use") { - profileOpen = null; + // the details close, renderAgents having drawn them again (#489: + // profileOpen dropped first, closeProfileDetail found nothing open and + // left them there, their × doing nothing) + closeProfileDetail(); closeProfiles(); // the agents, as they are now, in sight let msg = t(data.changed === 1 ? "{name} applied · {n} setting changed" : "{name} applied · {n} settings changed", { name, n: data.changed }); const lib = data.library; diff --git a/internal/gui/tests/README.md b/internal/gui/tests/README.md index f927004c..56230a10 100644 --- a/internal/gui/tests/README.md +++ b/internal/gui/tests/README.md @@ -357,8 +357,9 @@ chip's ↻ and × change nothing on a first click, reading "Overwrite?" and "Delete?" instead, and act on a second; the question goes on Escape or when left alone. The details' × closes them, the chip staying where it is; Escape closes the details, then the panel's list, and only then hides the panel; -the list closed with the details open opens again on the chips alone, as -after Apply. In Chromium and WebKit, English and Chinese: +the list closed with the details open opens again on the chips alone; Apply +closes the details, the tray's list opening again on the chips, and their × +closes them after it (#489). In Chromium and WebKit, English and Chinese: ```sh node --test --test-concurrency=1 internal/gui/tests/profile-details.test.cjs internal/gui/tests/panel-profiles.test.cjs internal/gui/tests/profile-confirm.test.cjs diff --git a/internal/gui/tests/profile-confirm.test.cjs b/internal/gui/tests/profile-confirm.test.cjs index 54a7e708..7b7c27eb 100644 --- a/internal/gui/tests/profile-confirm.test.cjs +++ b/internal/gui/tests/profile-confirm.test.cjs @@ -163,6 +163,30 @@ for (const engine of (process.env.BROWSER ? [process.env.BROWSER] : ["chromium", assert.equal(await detail.count(), 0, "closed with the list, the details stay closed"); assert.equal(await home.getAttribute("aria-expanded"), "false"); } else assert.deepEqual(calls, []); + + // Apply closes the details, for good, and × works after it (#489: + // the details stayed, or came back with the list, and their × did + // nothing) + calls.length = 0; // in the panel, the list is open from above + await homeName.click(); + await detail.waitFor(); + await detail.locator(".pd-apply").click(); + await page.waitForFunction(() => document.querySelector("#status").classList.contains("ok")); + assert.deepEqual(calls, ["use home"]); + await page.waitForTimeout(200); + assert.equal(await detail.count(), 0, "Apply closes the details"); + assert.equal(await home.getAttribute("aria-expanded"), "false"); + if (panel) { + assert.equal(await open.count(), 0, "Apply closes the panel's list"); + await openList(); + assert.equal(await detail.count(), 0, "after Apply the list opens on the chips"); + } + await homeName.click(); + await detail.waitFor(); + await detail.locator(".pd-close").click(); + await page.waitForTimeout(200); + assert.equal(await detail.count(), 0, "after Apply the details' × still closes them"); + assert.equal(await home.getAttribute("aria-expanded"), "false"); assert.deepEqual(errors, []); }); }