fix(ui): restrict edit to latest user message (#747)
fix(ui): restrict edit to latest user message (#747) Only the latest user turn shows the pencil/edit affordance. Older user messages remain read-only (copy + timestamp still work). Avoids the misleading implication that historical messages can be lightly edited when the actual action truncates the session and restarts the conversation from that point. Closes #744 Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
# Hermes Web UI -- Changelog
|
# Hermes Web UI -- Changelog
|
||||||
|
|
||||||
|
## [v0.50.97] — 2026-04-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Only the latest user message can be edited** — older user turns no longer show the pencil/edit affordance. This avoids implying that historical turns can be lightly edited when the actual action truncates the session and restarts the conversation from that point. (Closes #744)
|
||||||
|
|
||||||
## [v0.50.96] — 2026-04-19
|
## [v0.50.96] — 2026-04-19
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
10
static/ui.js
10
static/ui.js
@@ -1409,6 +1409,13 @@ function renderMessages(){
|
|||||||
if(msgContent(m)||m.attachments?.length||(m.role==='assistant'&&(hasTc||hasTu||_messageHasReasoningPayload(m)))) visWithIdx.push({m,rawIdx});
|
if(msgContent(m)||m.attachments?.length||(m.role==='assistant'&&(hasTc||hasTu||_messageHasReasoningPayload(m)))) visWithIdx.push({m,rawIdx});
|
||||||
rawIdx++;
|
rawIdx++;
|
||||||
}
|
}
|
||||||
|
let lastUserRawIdx=-1;
|
||||||
|
for(let i=visWithIdx.length-1;i>=0;i--){
|
||||||
|
if(visWithIdx[i].m&&visWithIdx[i].m.role==='user'){
|
||||||
|
lastUserRawIdx=visWithIdx[i].rawIdx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
const insertionAnchor=_compressionAnchorIndex(
|
const insertionAnchor=_compressionAnchorIndex(
|
||||||
visWithIdx,
|
visWithIdx,
|
||||||
compressionState ? compressionState.anchorMessageKey : sessionCompressionAnchorKey,
|
compressionState ? compressionState.anchorMessageKey : sessionCompressionAnchorKey,
|
||||||
@@ -1471,7 +1478,8 @@ function renderMessages(){
|
|||||||
filesHtml=`<div class="msg-files">${m.attachments.map(f=>`<div class="msg-file-badge">${li('paperclip',12)} ${esc(f)}</div>`).join('')}</div>`;
|
filesHtml=`<div class="msg-files">${m.attachments.map(f=>`<div class="msg-file-badge">${li('paperclip',12)} ${esc(f)}</div>`).join('')}</div>`;
|
||||||
}
|
}
|
||||||
const bodyHtml = isUser ? esc(String(content)).replace(/\n/g,'<br>') : renderMd(_stripXmlToolCallsDisplay(String(content)));
|
const bodyHtml = isUser ? esc(String(content)).replace(/\n/g,'<br>') : renderMd(_stripXmlToolCallsDisplay(String(content)));
|
||||||
const editBtn = isUser ? `<button class="msg-action-btn" title="${t('edit_message')}" onclick="editMessage(this)">${li('pencil',13)}</button>` : '';
|
const isEditableUser=isUser&&rawIdx===lastUserRawIdx;
|
||||||
|
const editBtn = isEditableUser ? `<button class="msg-action-btn" title="${t('edit_message')}" onclick="editMessage(this)">${li('pencil',13)}</button>` : '';
|
||||||
const retryBtn = isLastAssistant ? `<button class="msg-action-btn" title="${t('regenerate')}" onclick="regenerateResponse(this)">${li('rotate-ccw',13)}</button>` : '';
|
const retryBtn = isLastAssistant ? `<button class="msg-action-btn" title="${t('regenerate')}" onclick="regenerateResponse(this)">${li('rotate-ccw',13)}</button>` : '';
|
||||||
const copyBtn = `<button class="msg-copy-btn msg-action-btn" title="${t('copy')}" onclick="copyMsg(this)">${li('copy',13)}</button>`;
|
const copyBtn = `<button class="msg-copy-btn msg-action-btn" title="${t('copy')}" onclick="copyMsg(this)">${li('copy',13)}</button>`;
|
||||||
const tsVal=m._ts||m.timestamp;
|
const tsVal=m._ts||m.timestamp;
|
||||||
|
|||||||
9
tests/test_issue744.py
Normal file
9
tests/test_issue744.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
def test_only_latest_user_message_gets_edit_button():
|
||||||
|
src = pathlib.Path("static/ui.js").read_text(encoding="utf-8")
|
||||||
|
assert "let lastUserRawIdx=-1;" in src
|
||||||
|
assert "const isEditableUser=isUser&&rawIdx===lastUserRawIdx;" in src
|
||||||
|
assert "const editBtn = isEditableUser ?" in src
|
||||||
|
|
||||||
Reference in New Issue
Block a user