diff --git a/packages/webui/src/public/assistant.css b/packages/webui/src/public/assistant.css index fc219d6d2..98cd61b92 100644 --- a/packages/webui/src/public/assistant.css +++ b/packages/webui/src/public/assistant.css @@ -14,6 +14,7 @@ html[data-organizations] .assist-open:disabled{color:var(--muted);cursor:not-all html[data-organizations] .assist [data-assist-unread]:empty,html[data-organizations] .assist [data-assist-note]:empty{display:none} html[data-organizations] .assist [data-assist-unread] .note{margin:0} html[data-organizations] .assist [data-assist-note]{margin:0;font-size:13px;color:var(--muted)} +html[data-organizations] .assist [data-assist-note][data-refused]{color:var(--warning);font-weight:600} html[data-organizations] .assist-new{border:1px solid var(--line);border-radius:var(--r);background:var(--surface);padding:12px 14px;display:grid;gap:10px} html[data-organizations] .assist-new[hidden]{display:none} @@ -35,7 +36,7 @@ html[data-organizations] .assist-panes{display:grid;grid-template-columns:repeat html[data-organizations] .assist-panes[hidden]{display:none} html[data-organizations] .assist-pane{display:flex;flex-direction:column;min-width:0;min-height:0;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);overflow:hidden} html[data-organizations] .assist-pane-h{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);box-shadow:inset 0 3px 0 var(--org,var(--line));min-width:0;flex-wrap:wrap} -html[data-organizations] .assist-pane-h h2{margin:0;font-size:15px;font-weight:700;color:var(--strong,var(--text));overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1 1 120px} +html[data-organizations] .assist-pane-h h2{margin:0;font-size:15px;font-weight:700;color:var(--strong,var(--text));overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:5em;flex:1 1 0} html[data-organizations] .assist-pane-h h2:focus{outline:none} html[data-organizations] .assist-chips{display:inline-flex;gap:6px;flex-wrap:wrap;min-width:0} html[data-organizations] .assist-chips .ws-chip{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} diff --git a/packages/webui/src/public/assistant.js b/packages/webui/src/public/assistant.js index 46f42b9a6..9f7db0540 100644 --- a/packages/webui/src/public/assistant.js +++ b/packages/webui/src/public/assistant.js @@ -188,10 +188,16 @@ if (paused()) { mounted.timer = setTimeout(tick, POLL); return; } void draw(); } + // The line under the lead: how many panes are open, or why a thread was not opened (drawn as a warning). + function paintNote() { + const el = mounted.root.querySelector('[data-assist-note]'); + setText(el, mounted.notice || (mounted.panes.length ? `${mounted.panes.length} open, up to ${MAX}` : '')); + el?.toggleAttribute('data-refused', !!mounted.notice); + } function paintTop() { const { root, list, o, panes } = mounted; setHtml(root.querySelector('[data-assist-unread]'), list ? ws().unreadNote(o, [], 'assistant') : '
The organization list could not be read. Open panes only read.
'); - setText(root.querySelector('[data-assist-note]'), mounted.notice || (panes.length ? `${panes.length} open, up to ${MAX}` : '')); + paintNote(); const pick = root.querySelector('[data-assist-open]'); if (document.activeElement !== pick) { setHtml(pick, pickerHtml(list, mounted.got)); pick.value = ''; } const full = panes.length >= MAX; @@ -326,7 +332,7 @@ function add(key) { if (!mounted) return false; const p = place(key); - if (!p) { mounted.notice = REFUSED; setText(mounted.root.querySelector('[data-assist-note]'), REFUSED); return false; } + if (!p) { mounted.notice = REFUSED; paintNote(); return false; } mounted.notice = ''; mounted.show = key; writeUrl(); if (mounted.got) { paintTop(); drawPane(p); paintTabs(); layout(); } diff --git a/packages/webui/tests/assistant-threads-browser.test.mjs b/packages/webui/tests/assistant-threads-browser.test.mjs index df0e0193a..f9fd6c7e5 100644 --- a/packages/webui/tests/assistant-threads-browser.test.mjs +++ b/packages/webui/tests/assistant-threads-browser.test.mjs @@ -327,12 +327,14 @@ test('SP7: with three open, a fourth thread replaces the first pane with no unse await follow(b, `#/orgs/beta/projects/threads/${T.b1}`); await wait(`/not opened/.test(document.querySelector('[data-assist-note]').textContent)`); assert.match(await b.evaluate(`document.querySelector('[data-assist-note]').textContent`), /all 3 panes hold an unsent message/); + assert.equal(await b.evaluate(`document.querySelector('[data-assist-note]').hasAttribute('data-refused')`), true); assert.deepEqual(await b.evaluate(panes), [`alpha:${T.a1}`, `home:${T.h1}`, `alpha:${T.a2}`]); assert.deepEqual(await b.evaluate(`[${field(`alpha:${T.a1}`)}.value, ${field(`home:${T.h1}`)}.value, ${field(`alpha:${T.a2}`)}.value]`), ['alpha draft', 'home draft', 'kickoff draft']); assert.equal(await b.evaluate(query), `alpha:${T.a1},home:${T.h1},alpha:${T.a2}`); // Closing a pane clears the reason; the thread then opens. await b.evaluate(`${PANE(`home:${T.h1}`)}.querySelector('button[data-assist-close]').click()`); await wait(`!/not opened/.test(document.querySelector('[data-assist-note]').textContent)`); + assert.equal(await b.evaluate(`document.querySelector('[data-assist-note]').hasAttribute('data-refused')`), false); await follow(b, `#/orgs/beta/projects/threads/${T.b1}`); await wait(ready(`beta:${T.b1}`)); assert.deepEqual(await b.evaluate(panes), [`alpha:${T.a1}`, `alpha:${T.a2}`, `beta:${T.b1}`]);