mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 03:00:23 +00:00
fix: show collapsed session segment count
This commit is contained in:
committed by
nesquena-hermes
parent
c7272dbfc9
commit
4e71fb75d7
@@ -606,6 +606,7 @@ const LOCALES = {
|
||||
workspace_desc: 'Add and switch workspaces for your sessions.',
|
||||
session_meta_messages: (n) => `${n} msg${n === 1 ? '' : 's'}`,
|
||||
session_meta_children: (n) => `${n} child${n === 1 ? '' : 'ren'}`,
|
||||
session_meta_segments: (n) => `${n} segment${n === 1 ? '' : 's'}`,
|
||||
new_profile: 'New profile',
|
||||
transcript: 'Transcript',
|
||||
download_transcript: 'Download as Markdown',
|
||||
@@ -1626,6 +1627,7 @@ const LOCALES = {
|
||||
workspace_desc: 'セッション用のワークスペースを追加・切り替えします。',
|
||||
session_meta_messages: (n) => `${n} 件`,
|
||||
session_meta_children: (n) => `${n} 子`,
|
||||
session_meta_segments: (n) => `${n} セグメント`,
|
||||
new_profile: '新規プロファイル',
|
||||
transcript: 'トランスクリプト',
|
||||
download_transcript: 'Markdown としてダウンロード',
|
||||
@@ -2461,6 +2463,7 @@ const LOCALES = {
|
||||
workspace_desc: 'Добавляйте рабочие пространства и переключайтесь между ними в своих сеансах.',
|
||||
session_meta_messages: (n) => `${n} сообщ.`,
|
||||
session_meta_children: (n) => `${n} ${n === 1 ? 'дочерн.' : 'дочерн.'}`,
|
||||
session_meta_segments: (n) => `${n} сегм.`,
|
||||
new_profile: 'Новый профиль',
|
||||
transcript: 'Транскрипт',
|
||||
download_transcript: 'Скачать как Markdown',
|
||||
@@ -3415,6 +3418,7 @@ const LOCALES = {
|
||||
workspace_desc: 'Añade y cambia espacios de trabajo para tus sesiones.',
|
||||
session_meta_messages: (n) => `${n} mens.`,
|
||||
session_meta_children: (n) => `${n} ${n === 1 ? 'hijo' : 'hijos'}`,
|
||||
session_meta_segments: (n) => `${n} ${n === 1 ? 'segmento' : 'segmentos'}`,
|
||||
new_profile: 'Nuevo perfil',
|
||||
transcript: 'Transcripción',
|
||||
download_transcript: 'Descargar como Markdown',
|
||||
@@ -4347,6 +4351,7 @@ const LOCALES = {
|
||||
workspace_desc: 'Workspaces hinzufügen und wechseln.',
|
||||
session_meta_messages: (n) => `${n} Nachr.`,
|
||||
session_meta_children: (n) => `${n} ${n === 1 ? 'Subagent' : 'Subagents'}`,
|
||||
session_meta_segments: (n) => `${n} Segment${n === 1 ? '' : 'e'}`,
|
||||
new_profile: 'Neues Profil',
|
||||
transcript: 'Protokoll',
|
||||
download_transcript: 'Als Markdown herunterladen',
|
||||
@@ -5322,6 +5327,7 @@ const LOCALES = {
|
||||
workspace_desc: '为你的会话添加并切换工作区。',
|
||||
session_meta_messages: (n) => `${n} 条消息`,
|
||||
session_meta_children: (n) => `${n} 子会话`,
|
||||
session_meta_segments: (n) => `${n} 段`,
|
||||
new_profile: '新配置',
|
||||
transcript: '记录',
|
||||
download_transcript: '下载为 Markdown',
|
||||
@@ -6207,6 +6213,7 @@ const LOCALES = {
|
||||
current_task_list: '\u76ee\u524d\u4efb\u52d9\u6e05\u55ae',
|
||||
session_meta_messages: (n) => `${n} 則訊息`,
|
||||
session_meta_children: (n) => `${n} 則子`,
|
||||
session_meta_segments: (n) => `${n} 段`,
|
||||
new_profile: '\u65b0\u914d\u7f6e\u6a94',
|
||||
transcript: '\u8a18\u9304',
|
||||
download_transcript: '\u4e0b\u8f09\u8a18\u9304',
|
||||
@@ -6388,6 +6395,7 @@ const LOCALES = {
|
||||
provider_mismatch_warning: (provider) => `提供者不符:會話使用 ${provider}`,
|
||||
session_meta_messages: (n) => `${n} 則訊息`,
|
||||
session_meta_children: (n) => `${n} 則子`,
|
||||
session_meta_segments: (n) => `${n} 段`,
|
||||
settings_label_model: '\u9810\u8a2d\u6a21\u578b',
|
||||
skill_created: '\u6280\u80fd\u5df2\u5efa\u7acb',
|
||||
skill_file_load_failed: '\u8f09\u5165\u6a94\u6848\u5931\u6557\uff1a',
|
||||
@@ -7314,6 +7322,7 @@ const LOCALES = {
|
||||
workspace_desc: 'Adicionar e trocar workspaces para suas sessões.',
|
||||
session_meta_messages: (n) => `${n} msg${n === 1 ? '' : 's'}`,
|
||||
session_meta_children: (n) => `${n} child${n === 1 ? '' : 'ren'}`,
|
||||
session_meta_segments: (n) => `${n} segment${n === 1 ? '' : 's'}`,
|
||||
new_profile: 'Novo perfil',
|
||||
transcript: 'Transcrição',
|
||||
download_transcript: 'Baixar como Markdown',
|
||||
@@ -8232,6 +8241,7 @@ const LOCALES = {
|
||||
workspace_desc: '세션용 워크스페이스를 추가하고 전환합니다.',
|
||||
session_meta_messages: (n) => `${n} msg${n === 1 ? '' : 's'}`,
|
||||
session_meta_children: (n) => `${n} child${n === 1 ? '' : 'ren'}`,
|
||||
session_meta_segments: (n) => `${n} segment${n === 1 ? '' : 's'}`,
|
||||
new_profile: 'New profile',
|
||||
transcript: '대화 기록',
|
||||
download_transcript: 'Download as Markdown',
|
||||
|
||||
@@ -1835,6 +1835,16 @@ function _sessionLineageContainsSession(s, sid){
|
||||
return false;
|
||||
}
|
||||
|
||||
function _sessionSegmentCount(s){
|
||||
if(!s) return 0;
|
||||
const counts=[];
|
||||
if(typeof s._lineage_collapsed_count==='number') counts.push(s._lineage_collapsed_count);
|
||||
if(typeof s._compression_segment_count==='number') counts.push(s._compression_segment_count);
|
||||
if(Array.isArray(s._lineage_segments)) counts.push(s._lineage_segments.length);
|
||||
const count=Math.max(0,...counts.map(n=>Number.isFinite(n)?n:0));
|
||||
return count>1?count:0;
|
||||
}
|
||||
|
||||
function _sidebarLineageKeyForRow(s){
|
||||
if(!s) return null;
|
||||
return s._lineage_key||s._lineage_root_id||s.lineage_root_id||s.parent_session_id||s.session_id||null;
|
||||
@@ -2393,6 +2403,15 @@ function renderSessionListFromCache(){
|
||||
ts.className='session-time'+(hasAttentionState?' is-hidden':'');
|
||||
ts.textContent=hasAttentionState?'':_formatRelativeSessionTime(tsMs);
|
||||
titleRow.appendChild(title);
|
||||
const segmentCount=_sessionSegmentCount(s);
|
||||
if(segmentCount>0){
|
||||
const segmentCountEl=document.createElement('span');
|
||||
segmentCountEl.className='session-lineage-count';
|
||||
const segmentLabel=t('session_meta_segments', segmentCount);
|
||||
segmentCountEl.textContent=segmentLabel;
|
||||
segmentCountEl.title=segmentLabel;
|
||||
titleRow.appendChild(segmentCountEl);
|
||||
}
|
||||
const childCount=typeof s._child_session_count==='number'?s._child_session_count:(Array.isArray(s._child_sessions)?s._child_sessions.length:0);
|
||||
if(childCount>0){
|
||||
const childCountEl=document.createElement('span');
|
||||
|
||||
@@ -2654,6 +2654,8 @@ main.main.showing-logs > #mainLogs{display:flex;}
|
||||
.session-item.archived .session-title{font-style:italic;}
|
||||
|
||||
/* ── Subagent session tree (#494) ── */
|
||||
.session-lineage-count{display:inline-flex;align-items:center;justify-content:center;height:16px;font-size:10px;font-weight:600;padding:0 6px;border-radius:999px;background:rgba(148,163,184,.14);color:var(--muted);margin-left:6px;flex-shrink:0;user-select:none;cursor:default;}
|
||||
.session-item.active .session-lineage-count{color:var(--accent-text);background:rgba(255,255,255,.14);}
|
||||
.session-child-count{display:inline-flex;align-items:center;justify-content:center;height:16px;font-size:10px;font-weight:600;padding:0 6px;border-radius:999px;background:rgba(99,179,237,.16);color:#63b3ed;margin-left:6px;flex-shrink:0;user-select:none;cursor:pointer;}
|
||||
.session-child-count:hover{background:rgba(99,179,237,.26);color:#90cdf4;}
|
||||
.session-child-sessions{display:flex;flex-direction:column;gap:3px;margin-top:6px;margin-left:12px;padding-left:8px;border-left:1px solid var(--border,rgba(255,255,255,.1));}
|
||||
|
||||
@@ -208,3 +208,50 @@ console.log(JSON.stringify(rows));
|
||||
assert [row["session_id"] for row in rows] == ["telegram_parent", "webui_tip"]
|
||||
assert rows[1].get("_orphan_child_session") is True
|
||||
assert "_child_sessions" not in rows[0]
|
||||
|
||||
|
||||
def test_session_segment_count_prefers_visible_collapsed_backend_and_materialized_counts():
|
||||
js = SESSIONS_JS_PATH.read_text(encoding="utf-8")
|
||||
source = f"""
|
||||
const src = {js!r};
|
||||
function extractFunc(name) {{
|
||||
const re = new RegExp('function\\\\s+' + name + '\\\\s*\\\\(');
|
||||
const start = src.search(re);
|
||||
if (start < 0) throw new Error(name + ' not found');
|
||||
let i = src.indexOf('{{', start);
|
||||
let depth = 1; i++;
|
||||
while (depth > 0 && i < src.length) {{
|
||||
if (src[i] === '{{') depth++;
|
||||
else if (src[i] === '}}') depth--;
|
||||
i++;
|
||||
}}
|
||||
return src.slice(start, i);
|
||||
}}
|
||||
eval(extractFunc('_sessionSegmentCount'));
|
||||
const cases = [
|
||||
_sessionSegmentCount({{_lineage_collapsed_count:3, _compression_segment_count:2, _lineage_segments:[{{session_id:'a'}}, {{session_id:'b'}}]}}),
|
||||
_sessionSegmentCount({{_compression_segment_count:25}}),
|
||||
_sessionSegmentCount({{_lineage_segments:[{{session_id:'tip'}}, {{session_id:'root'}}, {{session_id:'older'}}]}}),
|
||||
_sessionSegmentCount({{_lineage_collapsed_count:1, _compression_segment_count:1}}),
|
||||
_sessionSegmentCount(null),
|
||||
];
|
||||
console.log(JSON.stringify(cases));
|
||||
"""
|
||||
assert json.loads(_run_node(source)) == [3, 25, 3, 0, 0]
|
||||
|
||||
|
||||
def test_sidebar_lineage_segment_badge_is_passive_and_localized():
|
||||
js = SESSIONS_JS_PATH.read_text(encoding="utf-8")
|
||||
css = (REPO_ROOT / "static" / "style.css").read_text(encoding="utf-8")
|
||||
assert "session-lineage-count" in js
|
||||
assert "const segmentCount=_sessionSegmentCount(s);" in js
|
||||
assert "t('session_meta_segments', segmentCount)" in js
|
||||
assert "titleRow.appendChild(segmentCountEl);" in js
|
||||
assert ".session-lineage-count{" in css
|
||||
assert "cursor:default" in css
|
||||
assert "session-lineage-count,.session-lineage-segments,.session-lineage-segment" not in js
|
||||
|
||||
|
||||
def test_session_meta_segments_locale_key_is_defined_for_sidebar_locales():
|
||||
i18n = (REPO_ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
|
||||
assert i18n.count("session_meta_segments:") >= i18n.count("session_meta_messages:")
|
||||
|
||||
Reference in New Issue
Block a user