diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js index b0ad1875e..579315329 100644 --- a/packages/webui/src/public/bus.js +++ b/packages/webui/src/public/bus.js @@ -506,8 +506,10 @@ const {res,json}=await decidePost(`${decideBase({ org: named })}/decisions/hire/start`,{business:org,hire:{op:'fire',level:'org',name,reason:FIRE_REASON}}); // SP5 review F7: a named organization's Fire went to that organization, so its outcome still // stands after the opened organization changes. - if(epoch!==orgEpoch&&!named){if(res?.type==='opaqueredirect')signOut();return;} - fireBusy=false;fireAsk=null; + // After a switch, busy and confirm state belong to whatever Fire started since; leave them alone. + const stale=epoch!==orgEpoch; + if(stale&&!named){if(res?.type==='opaqueredirect')signOut();return;} + if(!stale){fireBusy=false;fireAsk=null;} if(res?.type==='opaqueredirect'){signOut();return;} const where=named?` in ${orgName}`:''; if(res?.ok && json?.op==='resolved'){ diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css index d5eb75c6c..7b5cb57f9 100644 --- a/packages/webui/src/public/shell.css +++ b/packages/webui/src/public/shell.css @@ -700,6 +700,8 @@ html[data-organizations] .ws-agt td.ws-act .btn.small{min-height:0;padding:4px 1 html[data-organizations] .ws-agt .ws-fire-confirm{display:inline-flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px;white-space:normal} html[data-organizations] .ws-agt .t2.mono{overflow-wrap:anywhere} html[data-organizations] .ws-agt tr.on{background:color-mix(in srgb,var(--action) 10%,var(--surface))} +html[data-organizations] .ws-agt tr.on td:first-child{box-shadow:inset 3px 0 0 var(--action)} +@media (forced-colors:active){html[data-organizations] .ws-agt tr.on td:first-child{border-left:3px solid Highlight}} html[data-organizations] .ws-ochip{background:color-mix(in srgb,var(--org,var(--muted)) 14%,var(--surface))} html[data-organizations] .ws-ochip i{width:8px;height:8px;border-radius:999px;background:var(--org,var(--muted));flex:none} html[data-organizations] .ws-msrc{align-items:center;gap:5px;font-size:12px;color:var(--muted);margin-bottom:2px} diff --git a/packages/webui/tests/system-agents-browser.test.mjs b/packages/webui/tests/system-agents-browser.test.mjs index be3941798..c696e45b5 100644 --- a/packages/webui/tests/system-agents-browser.test.mjs +++ b/packages/webui/tests/system-agents-browser.test.mjs @@ -240,3 +240,19 @@ test('Cancel puts focus back on the row\'s Fire, which is labelled with the orga await wait(`document.activeElement === document.querySelector(${fire})`); assert.deepEqual(await b.evaluate('window.__posts'), []); }); + +test('a picked agent stays in the address through the state filter, and a scope that is not an organization id is refused', async t => { + const { b, wait } = await setup(t, { hash: '#/orgs/beta/agents?agent=research-2' }); + await wait(`${are(['beta:research-2', 'beta:pm'])} && document.querySelector('[data-ws-agents] [data-ws-astate="waiting"]')`); + await b.evaluate('document.querySelector(\'[data-ws-agents] [data-ws-astate="waiting"]\').click()'); + await wait(are(['beta:pm'])); + const q = new URLSearchParams((await b.evaluate('location.hash')).split('?')[1]); + assert.equal(q.get('agent'), 'research-2'); + assert.equal(q.get('state'), 'waiting'); + assert.equal(await b.evaluate('document.querySelector("[data-ws-agents] [aria-current]")'), null); + await b.evaluate('document.querySelector(\'[data-ws-agents] [data-ws-astate=""]\').click()'); + await wait(`${are(['beta:research-2', 'beta:pm'])} && document.querySelector('[data-ws-agent="beta:research-2"][aria-current="true"]')`); + const refused = await b.evaluate('window.MosaicWorkspace.agentsPage(new URLSearchParams(), { scope: "../beta" })'); + assert.match(refused, /data-ws-failed/); + assert.doesNotMatch(refused, /data-ws-agent=/); +});