From a917f3753abe622c0ede634888d4236e86ed07ac Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 22:47:38 +0800 Subject: [PATCH 1/8] =?UTF-8?q?fix(dashboard):=20=E4=BC=98=E5=8C=96=20Rece?= =?UTF-8?q?nt=20Active=20Sessions=20=E8=A1=A8=E6=A0=BC=E5=88=97=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E6=B6=88=E9=99=A4=E5=86=85=E5=AE=B9=E6=88=AA?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重分配列宽:Session ID 22%→16%,Client 6%→10%,Vendor Bind 8%→10%, Models 14%→16%,Vendors 12%→14%,解决 Client/Vendor Bind 每行溢出问题 - 供应商标签去文本前缀,改用颜色区分 API(蓝)/CC(绿) 类型,节省约 40% 列宽 - Models/Vendors 列允许标签换行,解除全局 nowrap 约束 - Models 显示上限 2→3,"+N" 标签添加 title tooltip 显示完整列表 - Vendors 增加上限 4,超出部分 "+N" + tooltip 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 53 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index d4647bb..9a3703b 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -407,6 +407,7 @@ def _build_favicon() -> bytes: border-bottom: 1px solid var(--border); } .session-table td { padding: 8px 12px; border-bottom: 1px solid var(--border-subtle); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .session-table td.cell-tags { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.8; vertical-align: middle; } .session-table tr:hover td { background: var(--bg-card-hover); } .session-table .session-key { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--accent-blue); cursor: default; white-space: normal; overflow: visible; } .session-id { line-height: 1.4; word-break: break-all; } @@ -417,6 +418,9 @@ def _build_favicon() -> bytes: background: rgba(88,166,255,.08); border: 1px solid rgba(88,166,255,.15); color: var(--text-secondary); } + .session-tag-cc { + background: rgba(63,185,80,.08); border-color: rgba(63,185,80,.15); + } .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.06); display: inline-block; vertical-align: middle; margin-left: 6px; } .success-bar-fill { height: 100%; border-radius: 2px; } /* ── Vendor Bind 选择器 ── */ @@ -641,16 +645,16 @@ def _build_favicon() -> bytes:
- - - + + + + - - - + - + + @@ -731,12 +735,15 @@ def _build_favicon() -> bytes: // _API_VENDORS 需与后端 native_api/handler.py::_VENDOR_LABEL 对齐, // 新增无 -native 后缀的 native vendor 时同步更新本集合。 const _API_VENDORS = new Set(['anthropic-native', 'openai', 'gemini']); +function isApiVendor(v) { return _API_VENDORS.has(v); } +function vendorShortName(v) { + if (!isValidLabel(v)) return v; + if (isApiVendor(v)) return v.endsWith('-native') ? v.slice(0, -'-native'.length) : v; + return v; +} function formatVendorLabel(v) { if (!isValidLabel(v)) return v; - if (_API_VENDORS.has(v)) { - const name = v.endsWith('-native') ? v.slice(0, -'-native'.length) : v; - return 'api | ' + name; - } + if (isApiVendor(v)) return 'api | ' + vendorShortName(v); return 'cc | ' + v; } @@ -1440,7 +1447,10 @@ def _build_favicon() -> bytes: var html = list.slice(0, max).map(function(c) { return '' + escapeHtml(c.trim()) + ''; }).join(''); - if (list.length > max) html += '+' + (list.length - max) + ''; + if (list.length > max) { + var fullList = list.map(function(c) { return c.trim(); }).join(', '); + html += '+' + (list.length - max) + ''; + } return html; } function formatCategories(cats) { @@ -1453,9 +1463,20 @@ def _build_favicon() -> bytes: } function formatVendorTags(vendors) { if (!vendors) return '–'; - return vendors.split(',').map(function(v) { - return '' + formatVendorLabel(v.trim()) + ''; + var list = vendors.split(','); + var max = 4; + var html = list.slice(0, max).map(function(v) { + var vt = v.trim(); + var name = vendorShortName(vt); + var fullLabel = formatVendorLabel(vt); + var cls = isApiVendor(vt) ? 'session-tag' : 'session-tag session-tag-cc'; + return '' + escapeHtml(name) + ''; }).join(''); + if (list.length > max) { + var fullList = list.map(function(v) { return formatVendorLabel(v.trim()); }).join(', '); + html += '+' + (list.length - max) + ''; + } + return html; } // ── Sessions Pagination State ── var allSessions = []; @@ -1513,8 +1534,8 @@ def _build_favicon() -> bytes: '' + '' + '' + - '' + - '' + + '' + + '' + '' + '' + '' + From fbe7d041802aa55171c14b0112231ad596e3ba44 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 23:05:44 +0800 Subject: [PATCH 2/8] =?UTF-8?q?fix(dashboard):=20=E4=BC=98=E5=8C=96=20Sess?= =?UTF-8?q?ion=20=E8=A1=A8=E6=A0=BC=E6=98=BE=E7=A4=BA=20=E2=80=94=20?= =?UTF-8?q?=E7=A6=81=E6=AD=A2=E6=8D=A2=E8=A1=8C=E3=80=81=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20Tooltip=20=E4=B8=8E=20Copy=20=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 cell-tags 换行样式,所有单元格统一 nowrap + ellipsis,行高统一 48px - Session ID 列缩窄至 12%,添加 ⧉ Copy 按钮一键拷贝 Session Key - Models/Vendors 单元格添加 title tooltip,鼠标悬停显示完整标签列表 - 修复 Success 列 "..." 问题:添加 cell-success 类禁用 ellipsis(进度条复合内容) - 进一步优化列宽:Vendors 14%→12%、Client/Vendor Bind 10%→12%、Models 16%→17% 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 40 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index 9a3703b..5c3c57e 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -407,10 +407,13 @@ def _build_favicon() -> bytes: border-bottom: 1px solid var(--border); } .session-table td { padding: 8px 12px; border-bottom: 1px solid var(--border-subtle); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } - .session-table td.cell-tags { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.8; vertical-align: middle; } .session-table tr:hover td { background: var(--bg-card-hover); } - .session-table .session-key { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--accent-blue); cursor: default; white-space: normal; overflow: visible; } - .session-id { line-height: 1.4; word-break: break-all; } + .session-table .session-key { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--accent-blue); cursor: default; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .session-id { display: flex; align-items: center; gap: 4px; } + .session-id-text { overflow: hidden; text-overflow: ellipsis; } + .copy-btn { background: none; border: none; color: var(--text-tertiary); cursor: pointer; padding: 2px; border-radius: 4px; font-size: 12px; line-height: 1; opacity: .5; flex-shrink: 0; } + .copy-btn:hover { opacity: 1; color: var(--accent-blue); background: rgba(88,166,255,.1); } + .copy-btn.copied { color: var(--accent-green); opacity: 1; } .session-meta { font-size: 10px; color: var(--text-tertiary); line-height: 1.2; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .session-tag { display: inline-block; font-size: 11px; padding: 2px 7px; @@ -421,6 +424,7 @@ def _build_favicon() -> bytes: .session-tag-cc { background: rgba(63,185,80,.08); border-color: rgba(63,185,80,.15); } + .session-table td.cell-success { overflow: visible; text-overflow: clip; } .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.06); display: inline-block; vertical-align: middle; margin-left: 6px; } .success-bar-fill { height: 100%; border-radius: 2px; } /* ── Vendor Bind 选择器 ── */ @@ -645,16 +649,16 @@ def _build_favicon() -> bytes:
' + relativeTime(s.last_active_ts) + '' + fmtNum(s.total_requests) + '' + fmtTokens(s.total_tokens) + '' + formatSessionTags(s.models, 2) + '' + formatVendorTags(s.vendors) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + (s.avg_duration_ms ? Math.round(s.avg_duration_ms) + 'ms' : '–') + '' + successBarHtml(s.success_rate) + '' + selectHtml + '
- + - - + + - - - + + + @@ -725,6 +729,13 @@ def _build_favicon() -> bytes: return String(n); } function fmtNum(n) { return n == null ? '–' : n.toLocaleString(); } +function copyText(btn, text) { + navigator.clipboard.writeText(text).then(function() { + btn.classList.add('copied'); + btn.textContent = '✓'; + setTimeout(function() { btn.classList.remove('copied'); btn.textContent = '⧉'; }, 1500); + }); +} function isValidLabel(s) { return typeof s === 'string' && s !== 'undefined' && s !== 'null' && s.trim() !== ''; } function now() { return new Date().toLocaleTimeString('zh-CN', {hour:'2-digit',minute:'2-digit',second:'2-digit'}); @@ -1526,7 +1537,10 @@ def _build_favicon() -> bytes: var selectHtml = buildBindSelect(s.session_key, boundVendors, sessionAvailableVendors); return '' + '' + '' + '' + - '' + - '' + + '' + + '' + '' + - '' + + '' + '' + '' + ''; From 9363232b68f521eeb54ce9a6021f3c737c577130 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 23:07:31 +0800 Subject: [PATCH 3/8] =?UTF-8?q?fix(dashboard):=20Avg=20Latency=20=E5=88=97?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=8F=AF=E8=AF=BB=E6=97=B6=E9=95=BF=E5=8D=95?= =?UTF-8?q?=E4=BD=8D=EF=BC=88ms/s/min=EF=BC=89=E8=87=AA=E5=8A=A8=E6=8D=A2?= =?UTF-8?q?=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - <1s 显示毫秒(如 234ms) - 1s~60s 显示秒(如 2.3s、15s) - >=60s 显示分钟+秒(如 2min 30s、5min) 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index 5c3c57e..a840e1b 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -737,6 +737,15 @@ def _build_favicon() -> bytes: }); } function isValidLabel(s) { return typeof s === 'string' && s !== 'undefined' && s !== 'null' && s.trim() !== ''; } +function fmtDuration(ms) { + if (ms == null) return '–'; + var s = ms / 1000; + if (s < 1) return Math.round(ms) + 'ms'; + if (s < 60) return s.toFixed(1).replace(/\\.0$/, '') + 's'; + var m = Math.floor(s / 60); + var sec = Math.round(s % 60); + return sec > 0 ? m + 'min ' + sec + 's' : m + 'min'; +} function now() { return new Date().toLocaleTimeString('zh-CN', {hour:'2-digit',minute:'2-digit',second:'2-digit'}); } @@ -1550,7 +1559,7 @@ def _build_favicon() -> bytes: '' + '' + '' + - '' + + '' + '' + '' + '' + From 5d6c2722e9fc02b8094c7612991104b4d4893b9d Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 23:12:48 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat(dashboard):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E8=A1=8C=E5=B1=95=E5=BC=80=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E5=8D=A1=E7=89=87=EF=BC=8C=E6=98=BE=E7=A4=BA=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 点击任意数据行展开/收起 detail-card(手风琴模式,仅展开一行) - 卡片以 grid 布局展示全部字段完整值:Session ID、Device、Account、 Models(全量标签)、Vendors(全量标签)、Avg Latency、Success Rate、Client - Session ID 列和 Vendor Bind 列点击事件隔离(stopPropagation), 避免误触展开 - 新增 toggleRow 函数,切换 .row-detail.open 类控制显隐 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 51 ++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index a840e1b..76d247b 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -425,6 +425,21 @@ def _build_favicon() -> bytes: background: rgba(63,185,80,.08); border-color: rgba(63,185,80,.15); } .session-table td.cell-success { overflow: visible; text-overflow: clip; } + /* ── 展开行 ── */ + .session-table tr.row-detail { display: none; } + .session-table tr.row-detail.open { display: table-row; } + .session-table tr.row-detail td { padding: 0; } + .detail-card { + padding: 14px 20px; margin: 4px 0; + background: rgba(18,22,30,.9); border: 1px solid var(--border); + border-radius: 10px; display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 10px 24px; font-size: 13px; + } + .detail-card .detail-item { display: flex; flex-direction: column; gap: 2px; } + .detail-card .detail-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .3px; } + .detail-card .detail-value { color: var(--text-primary); line-height: 1.4; word-break: break-all; } + .session-table tbody tr[data-row]:not(.row-detail) { cursor: pointer; } .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.06); display: inline-block; vertical-align: middle; margin-left: 6px; } .success-bar-fill { height: 100%; border-radius: 2px; } /* ── Vendor Bind 选择器 ── */ @@ -736,6 +751,14 @@ def _build_favicon() -> bytes: setTimeout(function() { btn.classList.remove('copied'); btn.textContent = '⧉'; }, 1500); }); } +function toggleRow(tr) { + var detail = tr.nextElementSibling; + if (!detail || !detail.classList.contains('row-detail')) return; + var wasOpen = detail.classList.contains('open'); + // close all open rows first + document.querySelectorAll('.session-table tr.row-detail.open').forEach(function(r) { r.classList.remove('open'); }); + if (!wasOpen) detail.classList.add('open'); +} function isValidLabel(s) { return typeof s === 'string' && s !== 'undefined' && s !== 'null' && s.trim() !== ''; } function fmtDuration(ms) { if (ms == null) return '–'; @@ -1544,8 +1567,11 @@ def _build_favicon() -> bytes: var parsed = parseSessionKey(s.session_key); var boundVendors = sessionBindMap[s.session_key]; var selectHtml = buildBindSelect(s.session_key, boundVendors, sessionAvailableVendors); - return '' + - '' + + '' + '' + '' + - '' + - '' + + '' + + '' + '' + '' + - '' + + '' + '' + - ''; + '' + + ''; }).join(''); } From 20f355633dbd03f7421def16286b91cc61688f56 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 23:15:31 +0800 Subject: [PATCH 5/8] =?UTF-8?q?chore(gitignore):=20=E6=B7=BB=E5=8A=A0=20.p?= =?UTF-8?q?laywright-mcp/=20=E5=88=B0=E5=BF=BD=E7=95=A5=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 75fec81..475b250 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,8 @@ config.yaml .claude/.prompts.md .python-version +# Playwright MCP +.playwright-mcp/ + # Log files (dual-write logging) coding-proxy.log* From f87f9e369f2808a31a898b6d2a15b1b231c43763 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Thu, 30 Apr 2026 23:56:14 +0800 Subject: [PATCH 6/8] =?UTF-8?q?fix(dashboard):=20=E4=BF=AE=E5=A4=8D=20Copy?= =?UTF-8?q?=20=E6=8C=89=E9=92=AE=E5=AF=BC=E8=87=B4=20JS=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E3=80=81=E5=B1=95=E5=BC=80=E5=8D=A1=E7=89=87=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E4=B8=8D=E5=8F=AF=E8=AF=BB=E5=8F=8A=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E6=98=BE=E7=A4=BA=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 copyText 内联值改为 copyFromParent 从 data-key 属性读取,避免 JSON 双引号在 onclick 中导致 JS 解析失败 - 优化展开卡片样式:渐变背景、蓝色边框、阴影、增大间距与圆角 - 页面初始化时立即加载版本号,修复直接进入 Sessions tab 时版本显示为 v-.-.- 的问题 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index ae815a4..3624f45 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -431,11 +431,12 @@ def _build_favicon() -> bytes: .session-table tr.row-detail.open { display: table-row; } .session-table tr.row-detail td { padding: 0; } .detail-card { - padding: 14px 20px; margin: 4px 0; - background: rgba(18,22,30,.9); border: 1px solid var(--border); - border-radius: 10px; display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 10px 24px; font-size: 13px; + padding: 16px 24px; margin: 6px 0; + background: linear-gradient(135deg, rgba(30,37,54,.95), rgba(22,28,40,.95)); + border: 1px solid rgba(88,166,255,.15); border-radius: 12px; + display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 14px 28px; font-size: 13px; + box-shadow: 0 4px 16px rgba(0,0,0,.3); } .detail-card .detail-item { display: flex; flex-direction: column; gap: 2px; } .detail-card .detail-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .3px; } @@ -745,7 +746,8 @@ def _build_favicon() -> bytes: return String(n); } function fmtNum(n) { return n == null ? '–' : n.toLocaleString(); } -function copyText(btn, text) { +function copyFromParent(btn) { + var text = btn.parentElement.getAttribute('data-key') || btn.parentElement.getAttribute('title') || ''; navigator.clipboard.writeText(text).then(function() { btn.classList.add('copied'); btn.textContent = '✓'; @@ -1573,9 +1575,9 @@ def _build_favicon() -> bytes: var sr = s.success_rate != null ? Math.round(s.success_rate) : null; return '' + '
' + - '
' + escapeHtml(parsed.session_id || s.session_key) + '
' + + '
' + + '' + escapeHtml(parsed.session_id || s.session_key) + '' + + '' + + '
' + '
' + 'dev:' + escapeHtml(shortId(parsed.device_id, 8)) + ' · acct:' + escapeHtml(shortId(parsed.account_uuid, 8)) + '
' + @@ -1534,10 +1548,10 @@ def _build_favicon() -> bytes: '
' + relativeTime(s.last_active_ts) + '' + fmtNum(s.total_requests) + '' + fmtTokens(s.total_tokens) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + (s.avg_duration_ms ? Math.round(s.avg_duration_ms) + 'ms' : '–') + '' + successBarHtml(s.success_rate) + '' + successBarHtml(s.success_rate) + '' + selectHtml + '' + formatCategories(s.client_categories) + '
' + fmtTokens(s.total_tokens) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + (s.avg_duration_ms ? Math.round(s.avg_duration_ms) + 'ms' : '–') + '' + fmtDuration(s.avg_duration_ms) + '' + successBarHtml(s.success_rate) + '' + selectHtml + '' + formatCategories(s.client_categories) + '
' + + var modelsFull = (s.models || '').split(',').map(function(c){return c.trim();}); + var vendorsFull = (s.vendors || '').split(',').map(function(v){return formatVendorLabel(v.trim());}); + var sr = s.success_rate != null ? Math.round(s.success_rate) : null; + return '
' + '
' + '' + escapeHtml(parsed.session_id || s.session_key) + '' + '' + @@ -1557,13 +1583,26 @@ def _build_favicon() -> bytes: '
' + relativeTime(s.last_active_ts) + '' + fmtNum(s.total_requests) + '' + fmtTokens(s.total_tokens) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + formatSessionTags(s.models, 3) + '' + formatVendorTags(s.vendors) + '' + fmtDuration(s.avg_duration_ms) + '' + successBarHtml(s.success_rate) + '' + selectHtml + '' + selectHtml + '' + formatCategories(s.client_categories) + '
' + + '
Session ID
' + escapeHtml(s.session_key) + '
' + + '
Device
' + escapeHtml(parsed.device_id || '–') + '
' + + '
Account
' + escapeHtml(parsed.account_uuid || '–') + '
' + + '
Last Active
' + relativeTime(s.last_active_ts) + '
' + + '
Requests
' + fmtNum(s.total_requests) + '
' + + '
Tokens
' + fmtTokens(s.total_tokens) + '
' + + '
Models
' + (modelsFull.length ? modelsFull.map(function(m){return '' + escapeHtml(m) + '';}).join(' ') : '–') + '
' + + '
Vendors
' + (vendorsFull.length ? vendorsFull.map(function(v){return '' + escapeHtml(v) + '';}).join(' ') : '–') + '
' + + '
Avg Latency
' + fmtDuration(s.avg_duration_ms) + '
' + + '
Success Rate
' + (sr != null ? sr + '%' : '–') + '
' + + '
Client
' + escapeHtml(s.client_categories || '–') + '
' + + '
' + - '
' + + '
' + '' + escapeHtml(parsed.session_id || s.session_key) + '' + - '' + + '' + '
' + '
' + 'dev:' + escapeHtml(shortId(parsed.device_id, 8)) + ' · acct:' + escapeHtml(shortId(parsed.account_uuid, 8)) + @@ -1780,6 +1782,10 @@ def _build_favicon() -> bytes: currentTab = initial; applyTabState(initial); syncTabUrl(initial); + // Load version immediately regardless of active tab + fetchJSON('/api/dashboard/summary?days=7').then(function(s) { + if (s && s.version) document.getElementById('version-badge').textContent = 'v' + s.version; + }).catch(function(){}); refresh(); // 仅加载初始页签的数据 setInterval(refresh, 600000); // 每 10 分钟刷新当前页签 })(); From 85e9b886f10be66a9122cd5e82fddca5e1588a78 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Fri, 1 May 2026 00:29:25 +0800 Subject: [PATCH 7/8] =?UTF-8?q?style(dashboard):=20=E9=87=8D=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E9=A1=B5=E7=AD=BE=E3=80=8CRecent=20Active=20Sessions?= =?UTF-8?q?=E3=80=8D=E4=B8=BA=E3=80=8CSessions=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index 3624f45..8bd09b9 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -559,7 +559,7 @@ def _build_favicon() -> bytes: @@ -655,12 +655,12 @@ def _build_favicon() -> bytes:
- +
- +
- Recent Active Sessions + Sessions Last 24h
@@ -1676,7 +1676,7 @@ def _build_favicon() -> bytes: let refreshing = false; let currentTab = 'overview'; const tabLoaded = { overview: false, sessions: false }; -const TAB_LABELS = { overview: 'Overview', sessions: 'Recent Active Sessions' }; +const TAB_LABELS = { overview: 'Overview', sessions: 'Sessions' }; async function refreshOverview() { const days = currentDays > 0 ? currentDays : 7; From 4ff8ecd7c3e6b6b60024c0c72d676cbfd66df0ad Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Fri, 1 May 2026 00:35:30 +0800 Subject: [PATCH 8/8] =?UTF-8?q?style(dashboard):=20=E5=A2=9E=E5=BC=BA=20Su?= =?UTF-8?q?ccess=20=E5=88=97=E8=BF=9B=E5=BA=A6=E6=9D=A1=E5=BA=95=E8=89=B2?= =?UTF-8?q?=E5=AF=B9=E6=AF=94=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- src/coding/proxy/server/dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coding/proxy/server/dashboard.py b/src/coding/proxy/server/dashboard.py index 8bd09b9..e3394f4 100644 --- a/src/coding/proxy/server/dashboard.py +++ b/src/coding/proxy/server/dashboard.py @@ -442,7 +442,7 @@ def _build_favicon() -> bytes: .detail-card .detail-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .3px; } .detail-card .detail-value { color: var(--text-primary); line-height: 1.4; word-break: break-all; } .session-table tbody tr[data-row]:not(.row-detail) { cursor: pointer; } - .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.06); display: inline-block; vertical-align: middle; margin-left: 6px; } + .success-bar { width: 56px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.12); display: inline-block; vertical-align: middle; margin-left: 6px; } .success-bar-fill { height: 100%; border-radius: 2px; } /* ── Vendor Bind 选择器 ── */ .bind-select {