From 4d1829add0ae04c4a80f05fb6dce53461d9310c3 Mon Sep 17 00:00:00 2001 From: lekt8 Date: Wed, 3 Jun 2026 03:07:31 +0800 Subject: [PATCH] Clear the composer draft when entering the New Chat / welcome state (#1408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking "New chat" (the brand/welcome navigation path) left the previous session's unsent draft in the composer (issue #1343). The direct model-picker path (createDirectChat) already cleared it, but the welcome path did not. Clear `#message` in chatRenderer.showWelcomeScreen() — the shared entry point for that state — resetting its autosized height and dispatching an `input` event so the send button / autosize listeners update. Switching between existing sessions loads them directly and does not call showWelcomeScreen, so genuine drafts are not erased. Co-authored-by: Claude Opus 4.8 (1M context) --- static/js/chatRenderer.js | 11 ++++++++++ tests/test_new_chat_clears_input.py | 34 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/test_new_chat_clears_input.py diff --git a/static/js/chatRenderer.js b/static/js/chatRenderer.js index 400632f..063889e 100644 --- a/static/js/chatRenderer.js +++ b/static/js/chatRenderer.js @@ -1217,6 +1217,17 @@ export function showWelcomeScreen() { const cc = document.getElementById('chat-container'); if (ws) ws.classList.remove('hidden'); if (cc) cc.classList.add('welcome-active'); + // Entering the New Chat / welcome state: discard any stale draft left in the + // composer from the previous session so the input starts empty (issue #1343). + // Switching between existing sessions loads them directly and does NOT call + // this, so genuine drafts are not erased. Reset the autosized height and fire + // an `input` event so the send button + autosize listeners update. + const _msg = document.getElementById('message'); + if (_msg) { + _msg.value = ''; + _msg.style.height = ''; + _msg.dispatchEvent(new Event('input', { bubbles: true })); + } // Re-trigger the L→R clip-wipe reveal on the welcome name each time the // welcome screen is shown (new session, deleted last session, etc.) — without // this, the CSS animation only fires on initial DOM insertion. diff --git a/tests/test_new_chat_clears_input.py b/tests/test_new_chat_clears_input.py new file mode 100644 index 0000000..7467d5a --- /dev/null +++ b/tests/test_new_chat_clears_input.py @@ -0,0 +1,34 @@ +"""Regression guard for issue #1343 — clicking "New chat" left the previous +session's draft text in the composer. + +The direct model-picker path (sessions.js:createDirectChat) already cleared the +input, but the brand/welcome New-Chat navigation path did not. The shared entry +point for that state is chatRenderer.js:showWelcomeScreen(), which now clears the +`#message` composer. Switching between existing sessions loads them directly and +does not call showWelcomeScreen, so real drafts aren't erased. + +chatRenderer.js pulls in browser globals, so it can't be imported under node; +this guards the fix at the source level so it can't be silently dropped. +""" +import re +from pathlib import Path + +SRC = (Path(__file__).resolve().parent.parent / "static/js/compare").parent / "chatRenderer.js" + + +def _show_welcome_body() -> str: + text = SRC.read_text(encoding="utf-8") + start = text.index("export function showWelcomeScreen()") + # Body runs until the next top-level `export function` / `function ` decl. + rest = text[start + len("export function showWelcomeScreen()"):] + m = re.search(r"\nexport function |\nfunction ", rest) + return rest[: m.start()] if m else rest + + +def test_new_chat_welcome_clears_the_composer(): + body = _show_welcome_body() + # Clears the draft value... + assert re.search(r"getElementById\(['\"]message['\"]\)", body) + assert re.search(r"\.value\s*=\s*['\"]['\"]", body), "must reset #message value" + # ...and notifies listeners (send button icon / autosize) of the change. + assert "new Event('input'" in body or 'new Event("input"' in body