Let the output "x" delete work when no model/session exists (#1431)
deleteMessage() bailed at `if (!sessionId) return;`, so the "x" on an output shown before a model/API was selected did nothing — there's no session yet (issue #1428). The session id is only needed for the server-side delete; without one (or with no persisted message ids) we now fall through to removing the DOM, so the "x" always at least dismisses the bubble. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4037,8 +4037,11 @@ import createResearchSynapse from './researchSynapse.js';
|
|||||||
const clickedIndex = allMsgs.indexOf(msgElement);
|
const clickedIndex = allMsgs.indexOf(msgElement);
|
||||||
if (clickedIndex < 0) return;
|
if (clickedIndex < 0) return;
|
||||||
|
|
||||||
|
// No early-out on a missing session: an output shown before any model was
|
||||||
|
// selected (issue #1428) has no session/persisted rows, but its "x" must
|
||||||
|
// still remove it. We only need the session id for the server-side delete
|
||||||
|
// below; without one we fall back to removing the DOM.
|
||||||
const sessionId = sessionModule.getCurrentSessionId();
|
const sessionId = sessionModule.getCurrentSessionId();
|
||||||
if (!sessionId) return;
|
|
||||||
|
|
||||||
const clickedIsUser = msgElement.classList.contains('msg-user');
|
const clickedIsUser = msgElement.classList.contains('msg-user');
|
||||||
|
|
||||||
@@ -4114,8 +4117,10 @@ import createResearchSynapse from './researchSynapse.js';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!msgIds.length) {
|
if (!msgIds.length || !sessionId) {
|
||||||
// Fallback: just remove DOM elements if no DB IDs available
|
// No persisted rows to delete (no DB IDs, or no session at all — e.g. an
|
||||||
|
// error output shown before a model was selected, #1428). Just remove the
|
||||||
|
// DOM so the "x" works regardless.
|
||||||
domToRemove.forEach(el => el.remove());
|
domToRemove.forEach(el => el.remove());
|
||||||
if (uiModule) uiModule.showToast('Message deleted');
|
if (uiModule) uiModule.showToast('Message deleted');
|
||||||
return;
|
return;
|
||||||
|
|||||||
34
tests/test_delete_message_no_session.py
Normal file
34
tests/test_delete_message_no_session.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
"""Regression guard for issue #1428 — the "x" on a chat output did nothing when
|
||||||
|
no model/API was selected.
|
||||||
|
|
||||||
|
deleteMessage() bailed at `if (!sessionId) return;`. An output shown before a
|
||||||
|
model is picked has no session and no persisted rows, so the early-out meant the
|
||||||
|
"x" never even removed the bubble from the DOM. The delete now falls through to
|
||||||
|
DOM removal when there's no session / no DB ids.
|
||||||
|
|
||||||
|
chat.js pulls in browser globals so it can't run under node; guard at the source.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
SRC = Path(__file__).resolve().parent.parent / "static/js/chat.js"
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_message_body() -> str:
|
||||||
|
text = SRC.read_text(encoding="utf-8")
|
||||||
|
start = text.index("export async function deleteMessage(")
|
||||||
|
rest = text[start:]
|
||||||
|
m = re.search(r"\n export (async )?function ", rest[1:])
|
||||||
|
return rest[: m.start() + 1] if m else rest
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_does_not_early_return_on_missing_session():
|
||||||
|
body = _delete_message_body()
|
||||||
|
# The bug was an unconditional early-out when no session existed.
|
||||||
|
assert not re.search(r"if\s*\(\s*!sessionId\s*\)\s*return\s*;", body), (
|
||||||
|
"deleteMessage must not early-return on a missing session (#1428)"
|
||||||
|
)
|
||||||
|
# The DOM-removal fallback must also fire when there's no session.
|
||||||
|
assert re.search(r"!msgIds\.length\s*\|\|\s*!sessionId", body), (
|
||||||
|
"DOM-removal fallback should cover the no-session case"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user