mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-07 05:56:17 -10:00
fix: dedupe aiui:prefill-composer listener across chat re-navigations (fixes #209)
Register the Code Studio prefill listener as a module-scope singleton via ensurePrefillListener() and remove it in cleanup(), preventing duplicate window handlers from stacking on repeated SPA navigation between /chat and /code-studio. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
This commit is contained in:
1 parent
90315326f7
commit
c4be709f8d
2 files changed
+58
-10
No files matched your search
@@ -22,6 +22,7 @@ let agents = [];
|
||||
let messageQueue = [];
|
||||
let focusMode = false;
|
||||
let sessionSelectHandler = null;
|
||||
let prefillHandler = null;
|
||||
let containerRef = null;
|
||||
let currentDeltaEl = null;
|
||||
let currentDeltaBodyEl = null;
|
||||
@@ -739,6 +740,26 @@ function setupResizeHandles(wrapper) {
|
||||
});
|
||||
}
|
||||
|
||||
// ── Prefill Composer Listener (singleton) ───────────────────────
|
||||
// Code Studio's "Send to Agent" dispatches a window-level
|
||||
// 'aiui:prefill-composer' event. This SPA calls render() on every
|
||||
// visit to /chat, so the listener is installed once at module scope
|
||||
// and guarded to avoid stacking duplicate handlers across navigations.
|
||||
function ensurePrefillListener() {
|
||||
if (prefillHandler) return;
|
||||
prefillHandler = (e) => {
|
||||
const text = e.detail && e.detail.text;
|
||||
if (!text) return;
|
||||
const el = document.getElementById('chat-input');
|
||||
if (!el) return;
|
||||
el.value = text;
|
||||
el.style.height = 'auto';
|
||||
el.style.height = Math.min(el.scrollHeight, 150) + 'px';
|
||||
el.focus();
|
||||
};
|
||||
window.addEventListener('aiui:prefill-composer', prefillHandler);
|
||||
}
|
||||
|
||||
// ── Main render (ES module entry point) ─────────────────────────
|
||||
export async function render(container) {
|
||||
injectStyles();
|
||||
@@ -881,16 +902,7 @@ export async function render(container) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); }
|
||||
});
|
||||
|
||||
window.addEventListener('aiui:prefill-composer', (e) => {
|
||||
const text = e.detail && e.detail.text;
|
||||
if (!text) return;
|
||||
const el = document.getElementById('chat-input');
|
||||
if (!el) return;
|
||||
el.value = text;
|
||||
el.style.height = 'auto';
|
||||
el.style.height = Math.min(el.scrollHeight, 150) + 'px';
|
||||
el.focus();
|
||||
});
|
||||
ensurePrefillListener();
|
||||
input.addEventListener('input', () => {
|
||||
input.style.height = 'auto';
|
||||
input.style.height = Math.min(input.scrollHeight, 150) + 'px';
|
||||
@@ -967,6 +979,10 @@ export function cleanup() {
|
||||
window.removeEventListener('aiui:session-select', sessionSelectHandler);
|
||||
sessionSelectHandler = null;
|
||||
}
|
||||
if (prefillHandler) {
|
||||
window.removeEventListener('aiui:prefill-composer', prefillHandler);
|
||||
prefillHandler = null;
|
||||
}
|
||||
currentSessionId = null;
|
||||
currentAgentName = null;
|
||||
isStreaming = false;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Tests for the chat prefill-composer listener lifecycle (issue #209).
|
||||
|
||||
The 'aiui:prefill-composer' listener must be registered as a module-scope
|
||||
singleton and torn down in cleanup(), so repeated SPA navigations between
|
||||
/code-studio and /chat do not stack duplicate handlers on window.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
VIEWS = Path("src/praisonaiui/templates/frontend/plugins/views")
|
||||
|
||||
|
||||
class TestChatPrefillListenerLifecycle:
|
||||
def test_module_scope_handler_declared(self):
|
||||
src = (VIEWS / "chat.js").read_text()
|
||||
assert "let prefillHandler = null;" in src
|
||||
|
||||
def test_ensure_prefill_listener_guard(self):
|
||||
src = (VIEWS / "chat.js").read_text()
|
||||
assert "function ensurePrefillListener()" in src
|
||||
assert "if (prefillHandler) return;" in src
|
||||
|
||||
def test_render_uses_singleton_not_inline_addlistener(self):
|
||||
src = (VIEWS / "chat.js").read_text()
|
||||
assert "ensurePrefillListener();" in src
|
||||
# The listener is added exactly once, inside the guard helper.
|
||||
assert src.count("window.addEventListener('aiui:prefill-composer'") == 1
|
||||
|
||||
def test_cleanup_removes_listener(self):
|
||||
src = (VIEWS / "chat.js").read_text()
|
||||
assert "window.removeEventListener('aiui:prefill-composer', prefillHandler)" in src
|
||||
assert src.count("prefillHandler = null;") >= 2
|
||||
Reference in new issue
Block a user