mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-13 11:10:37 +00:00
Merge #3203: clarify sidebar session tooltips
# Conflicts: # CHANGELOG.md
This commit is contained in:
@@ -3,6 +3,13 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.51.179] — 2026-05-30 — Release EY (stage-batch61 — custom-provider reasoning efforts + clearer sidebar tooltips)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Reasoning effort selector now appears for thinking-capable models served through custom API aggregators (New API, One API, etc.) that use non-standard model naming — bare names like `deepseek-v4-flash` or dot-separated `moonshotai.kimi-k2.5` rather than the OpenRouter-style `vendor/model` slash format. The heuristic now also strips a dot-vendor prefix and recognizes a `thinking`/`reasoning` token anywhere in the model name; plain non-reasoning models stay hidden as before (#3202).
|
||||
- Sidebar session row tooltips now explain the fork, prior-turn, child-session, and running/unread status badges, and hovering a truncated chat title shows the full title instead of the old "Double-click to rename" hint (#3203).
|
||||
|
||||
## [v0.51.178] — 2026-05-30 — Release EX (stage-batch60 — parallel sharded CI test runs)
|
||||
|
||||
### Changed
|
||||
|
||||
+35
-4
@@ -3339,6 +3339,36 @@ function _sessionTitleForForkParent(parentSid){
|
||||
return title;
|
||||
}
|
||||
|
||||
function _sessionFullTitleTooltip(rawTitle, cleanTitle){
|
||||
const fallback=String(cleanTitle||'Untitled').trim()||'Untitled';
|
||||
const full=String(rawTitle||fallback).trim()||fallback;
|
||||
if(full.startsWith('[SYSTEM:')) return fallback;
|
||||
return full;
|
||||
}
|
||||
|
||||
function _sessionForkTooltip(parentLabel){
|
||||
const parent=String(parentLabel||'').trim()||'unknown parent';
|
||||
return `Forked conversation — parent: ${parent}`;
|
||||
}
|
||||
|
||||
function _sessionLineageBadgeTooltip(label, canExpand){
|
||||
const base=String(label||'Prior turns').trim()||'Prior turns';
|
||||
return canExpand
|
||||
? `${base} — earlier context turns are collapsed here. Click to show or hide them.`
|
||||
: `${base} — earlier context turns are collapsed here.`;
|
||||
}
|
||||
|
||||
function _sessionChildBadgeTooltip(label){
|
||||
const base=String(label||'Child sessions').trim()||'Child sessions';
|
||||
return `${base} — child conversations spawned from this session. Click to show or hide them.`;
|
||||
}
|
||||
|
||||
function _sessionStateTooltip({isStreaming=false,hasUnread=false}={}){
|
||||
if(isStreaming) return 'Conversation is running';
|
||||
if(hasUnread) return 'Unread completion';
|
||||
return '';
|
||||
}
|
||||
|
||||
function _attachChildSessionsToSidebarRows(collapsedRows, rawSessions){
|
||||
const rows=(collapsedRows||[]).filter(s=>!_isChildSession(s)).map(s=>({...s}));
|
||||
const visibleBySid=new Map();
|
||||
@@ -4054,7 +4084,7 @@ function renderSessionListFromCache(){
|
||||
branchInd.className='session-branch-indicator';
|
||||
branchInd.innerHTML=li('git-branch',12);
|
||||
const parentLabel=_sessionTitleForForkParent(s.parent_session_id)||_truncatedSessionId(s.parent_session_id);
|
||||
branchInd.title=(typeof t==='function'?t('forked_from'):'Forked from')+' '+parentLabel;
|
||||
branchInd.title=_sessionForkTooltip(parentLabel);
|
||||
titleRow.appendChild(branchInd);
|
||||
}
|
||||
const title=document.createElement('span');
|
||||
@@ -4063,7 +4093,7 @@ function renderSessionListFromCache(){
|
||||
const titleMatched=Boolean(searchQueryRaw&&displayTitle.toLowerCase().includes(searchQueryRaw.toLowerCase()));
|
||||
if(titleMatched) _appendHighlightedText(title,displayTitle,searchQueryRaw,'session-search-hit');
|
||||
else title.textContent=displayTitle;
|
||||
title.title=readOnly?'Read-only imported session':'Double-click to rename';
|
||||
title.title=_sessionFullTitleTooltip(rawTitle,cleanTitle);
|
||||
const tsMs=_sessionTimestampMs(s);
|
||||
const ts=document.createElement('span');
|
||||
const hasAttentionState=isStreaming||hasUnread||Boolean(attention);
|
||||
@@ -4099,7 +4129,7 @@ function renderSessionListFromCache(){
|
||||
segmentCountEl.className='session-lineage-count'+(canExpandLineageSegments?' expandable':'');
|
||||
const segmentLabel=t('session_meta_segments', segmentCount);
|
||||
segmentCountEl.textContent=segmentLabel;
|
||||
segmentCountEl.title=segmentLabel;
|
||||
segmentCountEl.title=_sessionLineageBadgeTooltip(segmentLabel,canExpandLineageSegments);
|
||||
if(canExpandLineageSegments){
|
||||
segmentCountEl.setAttribute('role','button');
|
||||
segmentCountEl.setAttribute('tabindex','0');
|
||||
@@ -4128,7 +4158,7 @@ function renderSessionListFromCache(){
|
||||
childCountEl.className='session-child-count';
|
||||
const childLabel=t('session_meta_children', childCount);
|
||||
childCountEl.textContent=childLabel;
|
||||
childCountEl.title=childLabel;
|
||||
childCountEl.title=_sessionChildBadgeTooltip(childLabel);
|
||||
['pointerdown','pointerup','click'].forEach(ev=>childCountEl.addEventListener(ev,e=>e.stopPropagation()));
|
||||
childCountEl.onclick=(e)=>{
|
||||
e.stopPropagation();
|
||||
@@ -4317,6 +4347,7 @@ function renderSessionListFromCache(){
|
||||
state.className='session-attention-indicator session-state-indicator'+(isStreaming?' is-streaming':(hasUnread?' is-unread':''))+attentionDotClass;
|
||||
if(attention&&attention.title) state.title=attention.title;
|
||||
state.setAttribute('aria-hidden','true');
|
||||
state.title=_sessionStateTooltip({isStreaming,hasUnread});
|
||||
el.appendChild(state);
|
||||
// Single trigger button that opens a shared dropdown menu
|
||||
let actions=null;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Sidebar tooltip contract tests."""
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).parent.parent.resolve()
|
||||
SESSIONS_JS_PATH = REPO_ROOT / "static" / "sessions.js"
|
||||
|
||||
|
||||
def _sessions_js() -> str:
|
||||
return SESSIONS_JS_PATH.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_session_title_hover_shows_full_title_not_rename_hint():
|
||||
"""The truncated sidebar title needs a real full-title tooltip.
|
||||
|
||||
The old "Double-click to rename" title hid the only native hover affordance
|
||||
that can reveal a long chat title when badges/tags squeeze the row.
|
||||
"""
|
||||
js = _sessions_js()
|
||||
assert "Double-click to rename" not in js
|
||||
assert "title.title=_sessionFullTitleTooltip(rawTitle,cleanTitle);" in js
|
||||
|
||||
|
||||
def test_sidebar_status_badges_have_explanatory_tooltips():
|
||||
"""Compact badges/icons must explain what they mean, not repeat the chip text."""
|
||||
js = _sessions_js()
|
||||
assert "function _sessionFullTitleTooltip" in js
|
||||
assert "function _sessionForkTooltip" in js
|
||||
assert "function _sessionLineageBadgeTooltip" in js
|
||||
assert "function _sessionChildBadgeTooltip" in js
|
||||
assert "function _sessionStateTooltip" in js
|
||||
assert "branchInd.title=_sessionForkTooltip(parentLabel);" in js
|
||||
assert "segmentCountEl.title=_sessionLineageBadgeTooltip(segmentLabel,canExpandLineageSegments);" in js
|
||||
assert "childCountEl.title=_sessionChildBadgeTooltip(childLabel);" in js
|
||||
assert "state.title=_sessionStateTooltip({isStreaming,hasUnread});" in js
|
||||
Reference in New Issue
Block a user