feat: clinical handoff as the standard site modal, closes back to the chat
This commit is contained in:
parent
be889567f5
commit
c237826ef6
3 changed files with 32 additions and 9 deletions
|
|
@ -44,13 +44,7 @@
|
|||
<textarea id="assistant-input" rows="3" placeholder="Ask a focused clinical question..." autocomplete="off" aria-describedby="assistant-context-budget assistant-context-warning"></textarea>
|
||||
<p id="assistant-context-budget" class="assistant-muted" aria-live="polite">Loading conversation limit; history and draft are counted in UTF-16 code units. The server validates each request.</p>
|
||||
<div id="assistant-context-warning" role="alert" hidden></div>
|
||||
<div id="assistant-handoff-panel" hidden>
|
||||
<h3 id="assistant-handoff-heading">Clinical handoff</h3>
|
||||
<div id="assistant-handoff-preview" class="assistant-bubble" role="region" aria-labelledby="assistant-handoff-heading"></div>
|
||||
<textarea id="assistant-handoff-text" hidden readonly></textarea>
|
||||
<button id="btn-assistant-copy-handoff" class="btn-sm btn-ghost" type="button">Copy handoff</button>
|
||||
<p class="assistant-muted">Review this summary before using it. Your original chat is unchanged; nothing starts a new chat automatically.</p>
|
||||
</div>
|
||||
<textarea id="assistant-handoff-text" hidden readonly></textarea>
|
||||
<div class="assistant-composer-footer">
|
||||
<label class="assistant-check"><input type="checkbox" id="assistant-include-context" checked> retrieve broader context</label>
|
||||
<button id="btn-assistant-cancel" class="btn-sm btn-ghost" type="button" hidden><i class="fas fa-stop"></i> Cancel search</button>
|
||||
|
|
@ -96,4 +90,21 @@
|
|||
</aside>
|
||||
</div>
|
||||
|
||||
<!-- Clinical handoff dialog: uses the site's standard modal pattern. -->
|
||||
<div id="assistant-handoff-modal" class="modal hidden" role="dialog" aria-modal="true" aria-labelledby="assistant-handoff-heading">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="assistant-handoff-heading">Clinical handoff</h2>
|
||||
<button id="btn-assistant-handoff-close" class="modal-close" type="button" aria-label="Close handoff"><i class="fas fa-xmark"></i></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="assistant-handoff-preview" class="assistant-bubble" role="region" aria-labelledby="assistant-handoff-heading"></div>
|
||||
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:12px;flex-wrap:wrap;">
|
||||
<button id="btn-assistant-copy-handoff" class="btn-sm btn-primary" type="button">Copy handoff</button>
|
||||
<button id="btn-assistant-handoff-done" class="btn-sm btn-ghost" type="button">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet" href="/css/assistant.css">
|
||||
|
|
|
|||
|
|
@ -74,6 +74,13 @@ import {
|
|||
if (typeof showToast === 'function') showToast('Could not copy; select the summary text instead.', 'error');
|
||||
});
|
||||
});
|
||||
function closeHandoffModal() { setHandoff(''); }
|
||||
var handoffModal = document.getElementById('assistant-handoff-modal');
|
||||
if (handoffModal) {
|
||||
document.getElementById('btn-assistant-handoff-close').addEventListener('click', closeHandoffModal);
|
||||
document.getElementById('btn-assistant-handoff-done').addEventListener('click', closeHandoffModal);
|
||||
handoffModal.addEventListener('click', function(e) { if (e.target === handoffModal) closeHandoffModal(); });
|
||||
}
|
||||
if (input) input.addEventListener('input', updateConversationBudget);
|
||||
if (cancelBtn) cancelBtn.addEventListener('click', cancelAssistantSearch);
|
||||
if (copyBtn) copyBtn.addEventListener('click', copyLastAnswer);
|
||||
|
|
@ -878,7 +885,8 @@ import {
|
|||
preview.innerHTML = text ? renderMarkdown(text, []) : '';
|
||||
if (text) renderEmbeddedBlocks(preview);
|
||||
}
|
||||
document.getElementById('assistant-handoff-panel').hidden = !text;
|
||||
var modal = document.getElementById('assistant-handoff-modal');
|
||||
if (modal) modal.classList.toggle('hidden', !text);
|
||||
}
|
||||
|
||||
function requestHandoff() {
|
||||
|
|
|
|||
|
|
@ -273,7 +273,11 @@ test('handoff renders Markdown while preserving exact copy text and clearing on
|
|||
assert.equal(preview.querySelector('strong').textContent, 'Plan');
|
||||
assert.equal(preview.querySelector('li').textContent, 'Follow up');
|
||||
assert.equal(preview.querySelector('tbody td:last-child').textContent, '1.25 mg');
|
||||
assert.doesNotMatch(ui.document.getElementById('assistant-handoff-panel').textContent, /not.*verified clinical/i);
|
||||
assert.doesNotMatch(ui.document.getElementById('assistant-handoff-modal').textContent, /not.*verified clinical/i);
|
||||
assert.equal(ui.document.getElementById('assistant-handoff-modal').classList.contains('hidden'), false, 'modal visible');
|
||||
ui.document.getElementById('btn-assistant-handoff-done').click(); await tick();
|
||||
assert.equal(ui.document.getElementById('assistant-handoff-modal').classList.contains('hidden'), true, 'Close returns to the chat');
|
||||
assert.equal(ui.document.querySelectorAll('.assistant-msg').length, 1, 'chat state untouched');
|
||||
await loadChat(ui);
|
||||
assert.equal(raw.value, '');
|
||||
assert.equal(preview.textContent, '');
|
||||
|
|
|
|||
Loading…
Reference in a new issue