fix: show collapsed session segment count

This commit is contained in:
Dennis Soong
2026-05-08 23:38:09 +08:00
committed by nesquena-hermes
parent c7272dbfc9
commit 4e71fb75d7
4 changed files with 78 additions and 0 deletions
+10
View File
@@ -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',
+19
View File
@@ -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');
+2
View File
@@ -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));}
+47
View File
@@ -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:")