Implements the redesign from docs/ui-audit.html. Rearrangement only — no
feature was removed; every control that moved kept its handler, and the
gates that used to hide things now grey them out instead.
Navigation
* The rail is one flat list: the five Workspace sub-views sit at the top
level instead of behind an accordion, with Dashboard/Monitoring pinned
at the foot and Settings below them.
* Cowork and GraphRAG stay listed and greyed while no project is
selected, rather than vanishing and resizing the menu under the user.
* Monitoring keeps its eight sub-views in its own tab strip (unhidden)
instead of doubling the rail's length.
* _goto now moves the highlight itself, fixing a long-standing bug where
programmatic navigation left the rail pointing at the previous screen.
* Rail header gained the project picker and "New chat"; RECENTS lists the
active project's threads. Both are second views of existing state — the
Cowork toolbar button and the full History panel are untouched.
* Provider / language / theme moved from the top bar to an account row at
the foot of the rail (same widgets, same signals).
Screens
* Co4E: the flow tab strip is gone (per the design); Flow Status became a
toolbar toggle with its own way back, and the three icon-only tabs became
four labelled, foldable sections in one column. One flow open at a time
is the one capability this costs; background runs are unaffected.
* Dashboard: header split into two rows; cost promoted to a hero card.
* Monitoring Overview: one scrolling column of titled sections; the model
price table got its own full-width section instead of sharing a row with
the CPU meters.
* Settings and Task editor gained a section index down the left.
* Help dock: 84x64 launcher + chevron became one 26px dot that expands to
a labelled pill on hover; "hide to the edge" moved into the panel's menu.
Layout
* The window's minimum width dropped from 1453px to 768px. The main cause
was a QTabWidget taking its minimum from the widest page even when that
page is hidden, so Co4E was forcing Project and Cowork wide.
* Secondary panes fold themselves on a narrow window and restore when it
grows, never overriding a fold the user made.
* The long dialogs no longer scroll sideways at any font size.
Verification: tools/check_*.py build a real MainWindow offscreen against a
copy of ~/.cowork_local with the schedulers no-oped. check_design_parity.py
reads its checklist straight from the audit page's own proposals.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
24 lines
91 KiB
Python
24 lines
91 KiB
Python
"""Hand-written audit sections, extracted from 10-18.ui-audit.html.
|
||
|
||
GENERATED by tools/extract_handwritten.py — do not edit by hand; edit the
|
||
source HTML and re-run it. build_audit_page.py substitutes {{SHOT}} and
|
||
{{CONTROLS}} so those stay generated.
|
||
"""
|
||
|
||
SECTIONS = {
|
||
'monitoring-sự-kiện-bảo-mật': '<div class="bd">\n<p class="lead">Nhật ký lần agent chạm thứ nhạy cảm: lệnh bị chặn, truy cập ngoài sandbox.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>Trên</b>: 4 thẻ KPI · <b>Giữa</b>: ô tìm + nút ✨AI, lọc Agent/Hành động/Thời gian · <b>Dưới</b>: bảng cột Hành động dạng badge màu (thay cho ✕/✓ luôn giống nhau) + phân trang, nhấp dòng mở panel chi tiết bên phải.</p>\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab on">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab">Công cụ</div><div class="tab">Icon</div></div><div class="c grow"><div class="r tb"><div class="ttl">Sự kiện bảo mật</div><div class="grow"></div><div class="btn">⭳ Xuất CSV</div><div class="btn pri">⟳ Làm mới</div></div><div class="r"><div class="kpi2"><div class="ic blue">▦</div><div><b>1.247</b><span class="s">Tổng sự kiện · +12.3%</span></div></div><div class="kpi2"><div class="ic grn">◔</div><div><b>84</b><span class="s">Hôm nay · -8.1%</span></div></div><div class="kpi2"><div class="ic red">⛔</div><div><b>23</b><span class="s">Chặn lệnh · +3 mới</span></div></div><div class="kpi2"><div class="ic pur">🛡</div><div><b>156</b><span class="s">Chặn prompt · 12.5%</span></div></div></div><div class="r tb"><div class="srchwrap grow"><input class="inp" id="s10q" placeholder="🔍 Gõ câu hỏi hoặc từ khoá…"><span class="pill teal aibtn" id="s10ai">✨ AI</span></div><select class="btn" id="s10agent"><option value="">Agent</option><option>Security Agent</option><option>Cowork Agent</option><option value="schedule">schedule</option><option value="graphrag">graphrag</option><option>Code Agent</option></select><select class="btn" id="s10action"><option value="">Hành động</option><option value="dangerous_command">Lệnh nguy hiểm</option><option value="path_outside_sandbox">Path ngoài sandbox</option><option value="network_blocked">Mạng bị chặn</option><option value="secret_in_output">Tiết lộ bí mật</option></select><select class="btn" id="s10date"><option value="">Thời gian</option><option value="today">Hôm nay</option><option value="week">Tuần này</option><option value="month">Tháng này</option></select><div class="btn" id="s10clear">✕ Xoá lọc</div></div><div class="tblwrap grow"><table class="evtbl"><thead><tr><th>☐</th><th>Thời gian</th><th>Agent</th><th>Tài khoản</th><th>Máy</th><th>Hành động</th><th>Chi tiết chặn</th></tr></thead><tbody id="s10tb"></tbody></table></div><div class="r tb"><div class="s" id="s10count">Hiển thị 24 / 24 sự kiện</div><div class="grow"></div><div class="btn">‹</div><div class="btn pri">1</div><div class="btn">›</div></div></div></div><div class="c pane overlay hide" id="s10detail"></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n<script>\n(function(){\n var events=[\n {time:\'2026-08-11T17:29:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-11T12:01:00\',agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-11T11:01:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-11T06:05:00\',agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-10T19:42:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-10T17:18:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-10T11:53:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-10T15:47:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'network_blocked\',actionLabel:\'Mạng bị chặn\',detail:\'Chặn kết nối ra 203.0.113.44:8080\'},\n {time:\'2026-08-10T08:00:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-09T19:37:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'network_blocked\',actionLabel:\'Mạng bị chặn\',detail:\'Chặn kết nối ra 203.0.113.44:8080\'},\n {time:\'2026-08-09T14:53:00\',agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'secret_in_output\',actionLabel:\'Tiết lộ bí mật\',detail:\'Phát hiện chuỗi giống API key trong đầu ra, đã che\'},\n {time:\'2026-08-09T13:00:00\',agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-08T14:41:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'secret_in_output\',actionLabel:\'Tiết lộ bí mật\',detail:\'Phát hiện chuỗi giống API key trong đầu ra, đã che\'},\n {time:\'2026-08-08T11:38:00\',agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-07T12:50:00\',agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'network_blocked\',actionLabel:\'Mạng bị chặn\',detail:\'Chặn kết nối ra 203.0.113.44:8080\'},\n {time:\'2026-08-07T08:45:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'secret_in_output\',actionLabel:\'Tiết lộ bí mật\',detail:\'Phát hiện chuỗi giống API key trong đầu ra, đã che\'},\n {time:\'2026-08-06T10:07:00\',agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-06T11:15:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'secret_in_output\',actionLabel:\'Tiết lộ bí mật\',detail:\'Phát hiện chuỗi giống API key trong đầu ra, đã che\'},\n {time:\'2026-08-05T11:00:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'network_blocked\',actionLabel:\'Mạng bị chặn\',detail:\'Chặn kết nối ra 203.0.113.44:8080\'},\n {time:\'2026-08-05T17:16:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-05T09:07:00\',agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-04T15:46:00\',agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'dangerous_command\',actionLabel:\'Lệnh nguy hiểm\',detail:\'Chặn lệnh: rm -rf / --no-preserve-root\'},\n {time:\'2026-08-04T10:13:00\',agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'path_outside_sandbox\',actionLabel:\'Path ngoài sandbox\',detail:\'Chặn đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx\'},\n {time:\'2026-08-03T11:45:00\',agent:\'graphrag\',account:\'local\',machine:\'DESKTOP-DEMO\',action:\'secret_in_output\',actionLabel:\'Tiết lộ bí mật\',detail:\'Phát hiện chuỗi giống API key trong đầu ra, đã che\'}\n ];\n function pad(n){return String(n).padStart(2,\'0\');}\n function fmt(iso){var d=new Date(iso);return pad(d.getDate())+\'/\'+pad(d.getMonth()+1)+\' \'+pad(d.getHours())+\':\'+pad(d.getMinutes());}\n function fmtFull(iso){var d=new Date(iso);return pad(d.getDate())+\'/\'+pad(d.getMonth()+1)+\'/\'+d.getFullYear()+\' · \'+pad(d.getHours())+\':\'+pad(d.getMinutes())+\':\'+pad(d.getSeconds());}\n function ini(n){return n.split(\' \').map(function(w){return w[0];}).join(\'\').substring(0,2).toUpperCase();}\n function ac(n){if(n.indexOf(\'Security\')>=0)return \'red\';if(n.indexOf(\'Cowork\')>=0)return \'blue\';if(n===\'schedule\')return \'amb\';if(n===\'graphrag\')return \'pur\';if(n.indexOf(\'Code\')>=0)return \'grn\';return \'blue\';}\n function pcls(a){return ({dangerous_command:\'red\',path_outside_sandbox:\'grn\',network_blocked:\'teal\',secret_in_output:\'org\'})[a]||\'red\';}\n function statusInfo(a){return ({\n dangerous_command:{cls:\'pur\',icon:\'⊗\',label:\'Đã chặn\'},\n path_outside_sandbox:{cls:\'grn\',icon:\'▤\',label:\'Path chặn\'},\n network_blocked:{cls:\'teal\',icon:\'⦿\',label:\'Mạng chặn\'},\n secret_in_output:{cls:\'org\',icon:\'🔒\',label:\'Bí mật lộ\'}\n })[a]||{cls:\'pur\',icon:\'⊗\',label:\'Đã chặn\'};}\n var maxTs=events.reduce(function(m,e){return Math.max(m,new Date(e.time).getTime());},0);\n function render(list){\n var tb=document.getElementById(\'s10tb\');\n tb.innerHTML=list.map(function(ev,i){\n return \'<tr data-i="\'+i+\'"><td>☐</td><td>\'+fmt(ev.time)+\'</td>\'+\n \'<td><span class="av \'+ac(ev.agent)+\'">\'+ini(ev.agent)+\'</span>\'+ev.agent+\'</td>\'+\n \'<td>\'+ev.account+\'</td><td>\'+ev.machine+\'</td>\'+\n \'<td><span class="pill \'+pcls(ev.action)+\'">\'+ev.actionLabel+\'</span></td>\'+\n \'<td class="dt">\'+ev.detail+\'</td></tr>\';\n }).join(\'\');\n Array.prototype.forEach.call(tb.querySelectorAll(\'tr\'),function(tr){\n tr.addEventListener(\'click\',function(e){e.stopPropagation();openDetail(list[+tr.dataset.i],+tr.dataset.i);});\n });\n document.getElementById(\'s10count\').textContent=\'Hiển thị \'+list.length+\' / \'+events.length+\' sự kiện\';\n }\n function openDetail(ev,index){\n var d=document.getElementById(\'s10detail\');\n d.classList.remove(\'hide\');\n var st=statusInfo(ev.action);\n var sev=ev.action===\'dangerous_command\'?{t:\'CRITICAL\',c:\'red\'}:{t:\'MEDIUM\',c:\'amb\'};\n var evtId=\'evt_\'+ev.time.replace(/[^0-9]/g,\'\').substring(0,12)+\'_\'+String(index).padStart(3,\'0\');\n d.innerHTML=\n \'<div class="hd2 row">Chi tiết sự kiện<span class="pchev" id="s10close">✕</span></div>\'+\n \'<div class="dtl grow">\'+\n \'<div class="hd3">THÔNG TIN CHUNG</div>\'+\n \'<div class="fld"><span class="lbl">Thời gian</span><span class="val">\'+fmtFull(ev.time)+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Agent</span><span class="val"><span class="pill \'+ac(ev.agent)+\'">\'+ini(ev.agent)+\' \'+ev.agent+\'</span></span></div>\'+\n \'<div class="fld"><span class="lbl">Tài khoản</span><span class="val">\'+ev.account+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Máy</span><span class="val"><span class="mono">\'+ev.machine+\'</span></span></div>\'+\n \'<div class="hd3">HÀNH ĐỘNG</div>\'+\n \'<div class="fld"><span class="lbl">Loại</span><span class="val"><span class="tagn">\'+ev.actionLabel+\'</span></span></div>\'+\n \'<div class="fld"><span class="lbl">Trạng thái</span><span class="val"><span class="pill \'+st.cls+\'">\'+st.icon+\' \'+st.label+\'</span></span></div>\'+\n \'<div class="hd3">CHI TIẾT CHẶN</div>\'+\n \'<div class="code"><span>\'+ev.detail+\'</span><span class="cpy" id="s10copy">📋 Copy</span></div>\'+\n \'<div class="hd3">METADATA</div>\'+\n \'<div class="fld"><span class="lbl">Event ID</span><span class="val mono">\'+evtId+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Policy</span><span class="val">security_policy_v2</span></div>\'+\n \'<div class="fld"><span class="lbl">Severity</span><span class="val"><span class="pill \'+sev.c+\'">\'+sev.t+\'</span></span></div>\'+\n \'</div>\'+\n \'<div class="r tb pnlfoot"><div class="btn pri grow" id="s10closebtn">⭳ Đóng</div></div>\';\n document.getElementById(\'s10close\').addEventListener(\'click\',function(e){e.stopPropagation();closeDetail();});\n document.getElementById(\'s10closebtn\').addEventListener(\'click\',function(e){e.stopPropagation();closeDetail();});\n document.getElementById(\'s10copy\').addEventListener(\'click\',function(e){\n e.stopPropagation();\n var text=ev.detail;\n if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(text).catch(function(){});}\n var btn=document.getElementById(\'s10copy\');\n btn.textContent=\'✓ Copied\';\n setTimeout(function(){if(document.getElementById(\'s10copy\'))document.getElementById(\'s10copy\').textContent=\'📋 Copy\';},1500);\n });\n }\n function closeDetail(){\n var d=document.getElementById(\'s10detail\');\n d.classList.add(\'hide\');\n d.innerHTML=\'\';\n }\n document.addEventListener(\'click\',function(e){\n var d=document.getElementById(\'s10detail\');\n if(d.classList.contains(\'hide\'))return;\n if(d.contains(e.target))return;\n closeDetail();\n });\n function inRange(ev,bucket){\n if(!bucket)return true;\n var t=new Date(ev.time).getTime();\n var day=86400000;\n if(bucket===\'today\')return maxTs-t<day;\n if(bucket===\'week\')return maxTs-t<7*day;\n if(bucket===\'month\')return maxTs-t<31*day;\n return true;\n }\n function apply(){\n var ag=document.getElementById(\'s10agent\').value;\n var act=document.getElementById(\'s10action\').value;\n var dt=document.getElementById(\'s10date\').value;\n var q=document.getElementById(\'s10q\').value.trim().toLowerCase();\n var list=events.filter(function(ev){\n if(ag&&ev.agent!==ag)return false;\n if(act&&ev.action!==act)return false;\n if(!inRange(ev,dt))return false;\n if(q&&!(ev.agent.toLowerCase().indexOf(q)>=0||ev.actionLabel.toLowerCase().indexOf(q)>=0||ev.detail.toLowerCase().indexOf(q)>=0))return false;\n return true;\n });\n render(list);\n }\n document.getElementById(\'s10agent\').addEventListener(\'change\',apply);\n document.getElementById(\'s10action\').addEventListener(\'change\',apply);\n document.getElementById(\'s10date\').addEventListener(\'change\',apply);\n document.getElementById(\'s10q\').addEventListener(\'input\',apply);\n document.getElementById(\'s10ai\').addEventListener(\'click\',apply);\n document.getElementById(\'s10clear\').addEventListener(\'click\',function(){\n document.getElementById(\'s10agent\').value=\'\';\n document.getElementById(\'s10action\').value=\'\';\n document.getElementById(\'s10date\').value=\'\';\n document.getElementById(\'s10q\').value=\'\';\n render(events);\n });\n render(events);\n})();\n</script>\n\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Dải tab Monitoring bị ẩn sau accordion — không thấy 7 màn Giám sát còn lại từ đây.</li><li><b>Cột "Kết quả"</b> (✓/✕) trong bảng thật luôn hiện ✕ vì <code>audit_log.record("security_block",…)</code> luôn truyền <code>ok=False</code> — dư thừa, không phân biệt được gì.</li><li>KPI · lọc Agent/Hành động/Thời gian · phân trang · panel chi tiết đều là <b>tính năng mới</b>: bản thật hiện chỉ có 1 ô tìm + nút ✨AI + bảng cuộn (xem <code>ui/monitoring_tab.py:_wrap_with_filter</code>).</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Bỏ ẩn dải tab Monitoring (8 mục ngang hàng) — không đổi accordion nav rail.</li><li>Bỏ cột Kết quả luôn-giống-nhau; thay bằng cột <b>Hành động</b> dạng badge màu theo <code>name</code> thật (prompt/run_command/install_package).</li><li><span class="bad">Vượt phạm vi "chỉ sắp xếp lại"</span>: 4 thẻ KPI, 3 dropdown lọc, phân trang và panel chi tiết trượt — cần bổ sung logic đếm/lọc/phân trang ở <code>ui/monitoring_tab.py</code> trước khi hiện thực, và 2/4 loại "Hành động" (path ngoài sandbox, mạng chặn) chưa có nguồn ghi log thật.</li></ul></div>\n</div></div>',
|
||
'monitoring-lịch-sử-gọi-mcp': '<div class="bd">\n<p class="lead">Mọi lần agent gọi MCP server ngoài.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>Trên</b>: 4 thẻ KPI · <b>Giữa</b>: ô tìm + nút ✨AI, lọc Server/Kết quả/Thời gian · <b>Dưới</b>: bảng có badge Kết quả (✓/✕ phân biệt thật theo <code>ok</code>) + phân trang, nhấp dòng mở panel chi tiết bên phải. <b>Bảng hiện tại</b> (ảnh trên) không có ô lọc/tìm kiếm nào — khác biệt không chủ đích so với 2 màn log kia.</p>\n<div class="cap">Đề xuất — bố cục mới</div>\n<div class="wf">\n<div class="rail">\n<div class="menutog"><span>MENU</span><span class="chev">‹</span></div>\n<div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div>\n<div class="newbtn">+ Đoạn chat mới</div>\n<div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div>\n<div class="sep"></div>\n<div class="hd">RECENTS</div>\n<div class="scope">📁 Báo cáo tài chính Q3</div>\n<div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div>\n<div class="grow"></div>\n<div class="sep"></div>\n<div class="i">Dashboard</div><div class="i">Monitoring</div>\n<div class="acct">👤 local · Ollama ▾</div>\n</div>\n<div class="main">\n<div class="ttl">Monitoring</div>\n<div class="r tb">\n<div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab on">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab">Công cụ</div><div class="tab">Icon</div>\n</div>\n<div class="c grow">\n<div class="r tb">\n<div class="ttl">Lịch sử gọi MCP</div>\n<div class="grow"></div>\n<div class="btn">⭳ Xuất CSV</div><div class="btn pri">⟳ Làm mới</div>\n</div>\n<div class="r">\n<div class="kpi2"><div class="ic blue">▦</div><div><b>892</b><span class="s">Tổng cuộc gọi · +8.4%</span></div></div>\n<div class="kpi2"><div class="ic grn">✓</div><div><b>823</b><span class="s">Thành công · 92.3%</span></div></div>\n<div class="kpi2"><div class="ic red">✕</div><div><b>69</b><span class="s">Thất bại · 7.7%</span></div></div>\n<div class="kpi2"><div class="ic pur">◔</div><div><b>7</b><span class="s">Hôm nay · cuộc gọi</span></div></div>\n</div>\n<div class="r tb">\n<div class="srchwrap grow"><input class="inp" id="s11q" placeholder="🔍 Gõ câu hỏi hoặc từ khoá…"><span class="pill teal aibtn" id="s11ai">✨ AI</span></div>\n<select class="btn" id="s11server"><option value="">Server</option><option value="ms365">Microsoft 365</option><option value="github">GitHub</option><option value="filesystem">Filesystem</option><option value="search">Brave Search</option><option value="db">PostgreSQL</option></select>\n<select class="btn" id="s11status"><option value="">Kết quả</option><option value="ok">Thành công</option><option value="fail">Thất bại</option></select>\n<select class="btn" id="s11date"><option value="">Thời gian</option><option value="today">Hôm nay</option><option value="week">Tuần này</option><option value="month">Tháng này</option></select>\n<div class="btn" id="s11clear">✕ Xoá lọc</div>\n</div>\n<div class="tblwrap grow"><table class="evtbl"><thead><tr><th>Thời gian</th><th>Agent</th><th>Tài khoản</th><th>Máy</th><th>Tool</th><th>Kết quả</th><th>Chi tiết</th></tr></thead><tbody id="s11tb"></tbody></table></div>\n<div class="r tb"><div class="s" id="s11count">Hiển thị 25 / 25 cuộc gọi</div><div class="grow"></div><div class="btn">‹</div><div class="btn pri">1</div><div class="btn">›</div></div>\n</div>\n</div>\n<div class="c pane overlay hide" id="s11detail"></div>\n<div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n<script>\n(function(){\n var calls=[\n {time:\'2026-08-15T09:42:00\',tool:\'ms365__send_mail\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã gửi email đến nam.pdt@company.com — chủ đề "Báo cáo tuần Q3". Message-ID: <abc123@mail.company.com>\'},\n {time:\'2026-08-15T09:38:00\',tool:\'ms365__get_calendar_events\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Trả về 5 sự kiện trong 7 ngày tới. Cuộc họp kế tiếp: "Review Sprint 12" lúc 14:00 hôm nay.\'},\n {time:\'2026-08-15T09:31:00\',tool:\'github__search_repos\',server:\'github\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Tìm thấy 12 repo khớp từ khóa "vibeflow". Repo nổi bật: vibeflow/core (★ 1.2k).\'},\n {time:\'2026-08-15T09:20:00\',tool:\'filesystem__read_file\',server:\'filesystem\',ok:false,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Không thể đọc C:\\\\Users\\\\NamPDT\\\\Documents\\\\personal.xlsx — nằm ngoài sandbox được phép.\'},\n {time:\'2026-08-15T08:55:00\',tool:\'brave__web_search\',server:\'search\',ok:true,agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Trả về 8 kết quả cho "CVE-2026-1234". Nguồn hàng đầu: nvd.nist.gov.\'},\n {time:\'2026-08-15T08:40:00\',tool:\'postgres__query\',server:\'db\',ok:true,agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'SELECT 42 rows từ bảng usage_tracker. 1.2ms.\'},\n {time:\'2026-08-15T08:12:00\',tool:\'ms365__send_mail\',server:\'ms365\',ok:false,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Gửi thất bại: SMTP 550 — mailbox người nhận không tồn tại (unknown@invalid.com).\'},\n {time:\'2026-08-14T17:45:00\',tool:\'github__create_issue\',server:\'github\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã tạo issue #1284 "Fix flaky test in routing/orchestrator".\'},\n {time:\'2026-08-14T17:02:00\',tool:\'filesystem__write_file\',server:\'filesystem\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã ghi 1.024 bytes vào ./docs/ADR-004.md.\'},\n {time:\'2026-08-14T16:30:00\',tool:\'brave__web_search\',server:\'search\',ok:true,agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Trả về 6 kết quả cho "best practice API key rotation".\'},\n {time:\'2026-08-14T15:18:00\',tool:\'postgres__query\',server:\'db\',ok:false,agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Lỗi SQL: relation "audit_log_archive" does not exist. LINE 3: FROM audit_log_archive\'},\n {time:\'2026-08-14T14:44:00\',tool:\'ms365__get_user_profile\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Hồ sơ người dùng: Nam Phạm Đình Tú (nam.pdt@company.com), phòng ban: Engineering.\'},\n {time:\'2026-08-14T11:20:00\',tool:\'github__get_pull_request\',server:\'github\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'PR #1279: 3 files changed, +214 −38. Trạng thái: MERGED.\'},\n {time:\'2026-08-14T10:05:00\',tool:\'filesystem__list_dir\',server:\'filesystem\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Liệt kê 28 mục trong ./src/components.\'},\n {time:\'2026-08-13T18:22:00\',tool:\'brave__web_search\',server:\'search\',ok:true,agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Trả về 10 kết quả cho "OWASP Top 10 2026".\'},\n {time:\'2026-08-13T16:09:00\',tool:\'ms365__send_mail\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã gửi email đến hr@company.com — chủ đề "Đề xuất tuyển dụng Q4".\'},\n {time:\'2026-08-13T14:55:00\',tool:\'postgres__query\',server:\'db\',ok:true,agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'INSERT 1 row vào bảng daily_report. 0.8ms.\'},\n {time:\'2026-08-13T11:41:00\',tool:\'github__search_repos\',server:\'github\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Tìm thấy 5 repo khớp "react-query".\'},\n {time:\'2026-08-12T17:33:00\',tool:\'filesystem__read_file\',server:\'filesystem\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã đọc ./core/mcp_client.py (172 dòng).\'},\n {time:\'2026-08-12T15:07:00\',tool:\'ms365__get_calendar_events\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Trả về 3 sự kiện. Không có xung đột lịch.\'},\n {time:\'2026-08-12T12:30:00\',tool:\'brave__web_search\',server:\'search\',ok:false,agent:\'Security Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Hết thời gian chờ (timeout) sau 30s — server tìm kiếm không phản hồi.\'},\n {time:\'2026-08-12T09:15:00\',tool:\'github__create_issue\',server:\'github\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã tạo issue #1276 "Update model pricing table".\'},\n {time:\'2026-08-11T17:48:00\',tool:\'postgres__query\',server:\'db\',ok:true,agent:\'schedule\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'SELECT 128 rows từ bảng audit_log. 3.4ms.\'},\n {time:\'2026-08-11T14:26:00\',tool:\'ms365__send_mail\',server:\'ms365\',ok:true,agent:\'Cowork Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã gửi email đến team@company.com — chủ đề "Biên bản họp 11/08".\'},\n {time:\'2026-08-11T10:03:00\',tool:\'filesystem__write_file\',server:\'filesystem\',ok:true,agent:\'Code Agent\',account:\'local\',machine:\'DESKTOP-DEMO\',detail:\'Đã ghi 2.048 bytes vào ./docs/installation.md.\'}\n ];\n function pad(n){return String(n).padStart(2,\'0\');}\n function fmt(iso){var d=new Date(iso);return pad(d.getDate())+\'/\'+pad(d.getMonth()+1)+\' \'+pad(d.getHours())+\':\'+pad(d.getMinutes());}\n function fmtFull(iso){var d=new Date(iso);return pad(d.getDate())+\'/\'+pad(d.getMonth()+1)+\'/\'+d.getFullYear()+\' · \'+pad(d.getHours())+\':\'+pad(d.getMinutes())+\':\'+pad(d.getSeconds());}\n function ini(n){return n.split(\' \').map(function(w){return w[0];}).join(\'\').substring(0,2).toUpperCase();}\n function ac(n){if(n.indexOf(\'Security\')>=0)return \'red\';if(n.indexOf(\'Cowork\')>=0)return \'blue\';if(n===\'schedule\')return \'amb\';if(n===\'graphrag\')return \'pur\';if(n.indexOf(\'Code\')>=0)return \'grn\';return \'blue\';}\n var SERVER_META={\n ms365:{label:\'Microsoft 365\',badge:\'M365\',cls:\'blue\'},\n github:{label:\'GitHub\',badge:\'GH\',cls:\'dark\'},\n filesystem:{label:\'Filesystem\',badge:\'FS\',cls:\'olv\'},\n search:{label:\'Brave Search\',badge:\'BR\',cls:\'pur\'},\n db:{label:\'PostgreSQL\',badge:\'DB\',cls:\'teal\'}\n };\n function serverMeta(s){return SERVER_META[s]||{label:s,badge:s.substring(0,2).toUpperCase(),cls:\'amb\'};}\n function toolShort(t){return t.indexOf(\'__\')>=0?t.split(\'__\')[1]:t;}\n var maxTs=calls.reduce(function(m,c){return Math.max(m,new Date(c.time).getTime());},0);\n function render(list){\n var tb=document.getElementById(\'s11tb\');\n tb.innerHTML=list.map(function(c,i){\n var meta=serverMeta(c.server);\n var resultPill=c.ok?\'<span class="pill grn">✓ Thành công</span>\':\'<span class="pill red">✕ Thất bại</span>\';\n return \'<tr data-i="\'+i+\'">\'+\n \'<td>\'+fmt(c.time)+\'</td>\'+\n \'<td><span class="av \'+ac(c.agent)+\'">\'+ini(c.agent)+\'</span>\'+c.agent+\'</td>\'+\n \'<td>\'+c.account+\'</td>\'+\n \'<td>\'+c.machine+\'</td>\'+\n \'<td><span class="av \'+meta.cls+\'">\'+meta.badge+\'</span>\'+toolShort(c.tool)+\' <span class="s">\'+meta.label+\'</span></td>\'+\n \'<td>\'+resultPill+\'</td>\'+\n \'<td class="dt">\'+c.detail+\'</td>\'+\n \'</tr>\';\n }).join(\'\');\n Array.prototype.forEach.call(tb.querySelectorAll(\'tr\'),function(tr){\n tr.addEventListener(\'click\',function(e){e.stopPropagation();openDetail(list[+tr.dataset.i],+tr.dataset.i);});\n });\n document.getElementById(\'s11count\').textContent=\'Hiển thị \'+list.length+\' / \'+calls.length+\' cuộc gọi\';\n }\n function openDetail(c,index){\n var d=document.getElementById(\'s11detail\');\n d.classList.remove(\'hide\');\n var meta=serverMeta(c.server);\n var resultPill=c.ok?\'<span class="pill grn">✓ Thành công</span>\':\'<span class="pill red">✕ Thất bại</span>\';\n var evtId=\'evt_\'+c.time.replace(/[^0-9]/g,\'\').substring(0,12)+\'_\'+String(index).padStart(3,\'0\');\n d.innerHTML=\n \'<div class="hd2 row">Chi tiết cuộc gọi MCP<span class="pchev" id="s11close">✕</span></div>\'+\n \'<div class="dtl grow">\'+\n \'<div class="hd3">THÔNG TIN CHUNG</div>\'+\n \'<div class="fld"><span class="lbl">Thời gian</span><span class="val">\'+fmtFull(c.time)+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Tool</span><span class="val mono">\'+c.tool+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Server</span><span class="val"><span class="av \'+meta.cls+\'">\'+meta.badge+\'</span> \'+meta.label+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Agent</span><span class="val"><span class="pill \'+ac(c.agent)+\'">\'+ini(c.agent)+\' \'+c.agent+\'</span></span></div>\'+\n \'<div class="fld"><span class="lbl">Tài khoản</span><span class="val">\'+c.account+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Máy</span><span class="val"><span class="mono">\'+c.machine+\'</span></span></div>\'+\n \'<div class="hd3">TRẠNG THÁI</div>\'+\n \'<div class="fld"><span class="lbl">Kết quả</span><span class="val">\'+resultPill+\'</span></div>\'+\n \'<div class="hd3">OUTPUT / CHI TIẾT</div>\'+\n \'<div class="code"><span>\'+c.detail+\'</span><span class="cpy" id="s11copy">📋 Copy</span></div>\'+\n \'<div class="hd3">METADATA</div>\'+\n \'<div class="fld"><span class="lbl">Call ID</span><span class="val mono">\'+evtId+\'</span></div>\'+\n \'<div class="fld"><span class="lbl">Loại log</span><span class="val"><span class="tagn">mcp_call</span></span></div>\'+\n \'<div class="fld"><span class="lbl">Namespace</span><span class="val mono">\'+c.server+\'__\'+toolShort(c.tool)+\'</span></div>\'+\n \'</div>\'+\n \'<div class="r tb pnlfoot"><div class="btn pri grow" id="s11closebtn">⭳ Đóng</div></div>\';\n document.getElementById(\'s11close\').addEventListener(\'click\',function(e){e.stopPropagation();closeDetail();});\n document.getElementById(\'s11closebtn\').addEventListener(\'click\',function(e){e.stopPropagation();closeDetail();});\n document.getElementById(\'s11copy\').addEventListener(\'click\',function(e){\n e.stopPropagation();\n var text=c.detail;\n if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(text).catch(function(){});}\n var btn=document.getElementById(\'s11copy\');\n btn.textContent=\'✓ Copied\';\n setTimeout(function(){if(document.getElementById(\'s11copy\'))document.getElementById(\'s11copy\').textContent=\'📋 Copy\';},1500);\n });\n }\n function closeDetail(){\n var d=document.getElementById(\'s11detail\');\n d.classList.add(\'hide\');\n d.innerHTML=\'\';\n }\n document.addEventListener(\'click\',function(e){\n var d=document.getElementById(\'s11detail\');\n if(d.classList.contains(\'hide\'))return;\n if(d.contains(e.target))return;\n closeDetail();\n });\n function inRange(c,bucket){\n if(!bucket)return true;\n var t=new Date(c.time).getTime();\n var day=86400000;\n if(bucket===\'today\')return maxTs-t<day;\n if(bucket===\'week\')return maxTs-t<7*day;\n if(bucket===\'month\')return maxTs-t<31*day;\n return true;\n }\n function apply(){\n var srv=document.getElementById(\'s11server\').value;\n var st=document.getElementById(\'s11status\').value;\n var dt=document.getElementById(\'s11date\').value;\n var q=document.getElementById(\'s11q\').value.trim().toLowerCase();\n var list=calls.filter(function(c){\n if(srv&&c.server!==srv)return false;\n if(st===\'ok\'&&!c.ok)return false;\n if(st===\'fail\'&&c.ok)return false;\n if(!inRange(c,dt))return false;\n if(q&&!((c.tool+\' \'+c.server+\' \'+c.agent+\' \'+c.detail).toLowerCase().indexOf(q)>=0))return false;\n return true;\n });\n render(list);\n }\n document.getElementById(\'s11server\').addEventListener(\'change\',apply);\n document.getElementById(\'s11status\').addEventListener(\'change\',apply);\n document.getElementById(\'s11date\').addEventListener(\'change\',apply);\n document.getElementById(\'s11q\').addEventListener(\'input\',apply);\n document.getElementById(\'s11ai\').addEventListener(\'click\',apply);\n document.getElementById(\'s11clear\').addEventListener(\'click\',function(){\n document.getElementById(\'s11server\').value=\'\';\n document.getElementById(\'s11status\').value=\'\';\n document.getElementById(\'s11date\').value=\'\';\n document.getElementById(\'s11q\').value=\'\';\n render(calls);\n });\n render(calls);\n})();\n</script>\n\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Dải tab Monitoring bị ẩn sau accordion — không thấy 7 màn Giám sát còn lại từ đây.</li><li>Bảng <b>Lịch sử gọi MCP</b> thật hiện <b>không có ô tìm/lọc nào</b> — còn thiếu hơn cả Sự kiện bảo mật: <code>ui/monitoring_tab.py:166-168</code> tạo thẳng <code>self.mcp_table = _EventTable()</code> rồi thêm vào tab, không bọc qua <code>_wrap_with_filter</code> như Sự kiện bảo mật/Nhật ký hành động — đúng như đã ghi ở ảnh Hiện tại.</li><li>KPI · lọc Server/Kết quả/Thời gian · phân trang · panel chi tiết đều là <b>tính năng mới</b>: bản thật chỉ có bảng 7 cột (Thời gian/Vai trò/Tài khoản/Máy/Tên/Kết quả/Chi tiết), không tìm không lọc không phân trang (xem <code>ui/monitoring_tab.py:_EventTable</code>).</li><li>5 server trong bảng mẫu (M365/GitHub/Filesystem/Brave Search/PostgreSQL) chỉ là ví dụ minh hoạ lấy từ docstring <code>core/mcp_client.py</code> — server thật phụ thuộc Admin đã cấu hình connector nào ở Settings, không có sẵn mặc định.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Bỏ ẩn dải tab Monitoring (8 mục ngang hàng) — không đổi accordion nav rail.</li><li>Thêm ô tìm kiếm + nút ✨AI cho bảng này để đồng bộ với 2 bảng log kia — hiện là bảng log duy nhất trong 3 bảng không có tìm kiếm.</li><li><span class="bad">Vượt phạm vi "chỉ sắp xếp lại"</span>: 4 thẻ KPI, 3 dropdown lọc (Server/Kết quả/Thời gian), phân trang và panel chi tiết trượt — cần bổ sung logic đếm/lọc/phân trang ở <code>ui/monitoring_tab.py</code> trước khi hiện thực; danh sách server chỉ minh hoạ, không phải cấu hình mặc định.</li></ul></div>\n</div></div>',
|
||
'monitoring-nhật-ký-hành-động': '<div class="bd">\n<p class="lead">Nhật ký cấp ứng dụng: ai đổi cấu hình, ai chạy task.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab on">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab">Công cụ</div><div class="tab">Icon</div></div><div class="c grow"><div class="r tb"><div class="ttl">Nhật ký hành động</div><div class="grow"></div><div class="btn">⭳ Xuất CSV</div><div class="btn pri">⟳ Làm mới</div></div><div class="r"><div class="kpi2"><div class="ic blue">▤</div><div><b>25</b><span class="s">Tổng sự kiện · +6.2%</span></div></div><div class="kpi2"><div class="ic grn">✓</div><div><b>19</b><span class="s">Thành công · 76%</span></div></div><div class="kpi2"><div class="ic red">✕</div><div><b>6</b><span class="s">Thất bại · 24%</span></div></div><div class="kpi2"><div class="ic pur">🛡</div><div><b>4</b><span class="s">Chặn bảo mật</span></div></div></div><div class="r tb"><div class="srchwrap grow"><input class="inp" placeholder="🔍 Tìm hành động, agent, chi tiết…"><span class="pill teal aibtn">✨ AI</span></div><select class="btn"><option value="">Tất cả loại</option><option>Công cụ</option><option>Gọi MCP</option><option>Chặn bảo mật</option><option>Quyền</option></select><select class="btn"><option value="">Tất cả trạng thái</option><option>Thành công</option><option>Thất bại</option></select><select class="btn"><option value="">Tất cả thời gian</option><option>Hôm nay</option><option>Tuần này</option><option>Tháng này</option></select><div class="btn">✕ Xóa lọc</div></div><div class="tblwrap grow"><table class="evtbl"><thead><tr><th>Thời gian</th><th>Agent</th><th>Loại</th><th>Máy</th><th>Hành động</th><th>Kết quả</th><th>Chi tiết</th></tr></thead><tbody><tr><td>15/08 · 09:42</td><td><span class="av blue">CA</span>Cowork Agent</td><td><span class="pill teal">Gọi MCP</span></td><td>DESKTOP-DEMO</td><td>ms365__send_mail</td><td><span class="pill grn">✓ Thành công</span></td><td class="dt">Đã gửi email đến nam.pdt@company.com — chủ đề "Báo cáo tuần Q3".</td></tr><tr><td>15/08 · 09:38</td><td><span class="av blue">CA</span>Cowork Agent</td><td><span class="pill blue">Công cụ</span></td><td>DESKTOP-DEMO</td><td>read_file</td><td><span class="pill grn">✓ Thành công</span></td><td class="dt">Đã đọc ./docs/installation.md (172 dòng).</td></tr><tr><td>15/08 · 09:31</td><td><span class="av red">SA</span>Security Agent</td><td><span class="pill pur">Chặn bảo mật</span></td><td>DESKTOP-DEMO</td><td>dangerous_command</td><td><span class="pill red">✕ Thất bại</span></td><td class="dt">Chặn lệnh: rm -rf / --no-preserve-root</td></tr><tr><td>15/08 · 09:20</td><td><span class="av blue">CA</span>Cowork Agent</td><td><span class="pill gry">Quyền</span></td><td>DESKTOP-DEMO</td><td>path_outside_sandbox</td><td><span class="pill red">✕ Thất bại</span></td><td class="dt">Chặn đọc C:\\Users\\NamPDT\\Documents\\personal.xlsx — ngoài sandbox.</td></tr><tr><td>15/08 · 08:55</td><td><span class="av red">SA</span>Security Agent</td><td><span class="pill teal">Gọi MCP</span></td><td>DESKTOP-DEMO</td><td>brave__web_search</td><td><span class="pill grn">✓ Thành công</span></td><td class="dt">Trả về 8 kết quả cho "CVE-2026-1234".</td></tr><tr><td>14/08 · 17:45</td><td><span class="av amb">SC</span>schedule</td><td><span class="pill blue">Công cụ</span></td><td>DESKTOP-DEMO</td><td>run_command</td><td><span class="pill grn">✓ Thành công</span></td><td class="dt">python scripts/report.py — thoát mã 0.</td></tr></tbody></table></div><div class="r tb"><div class="s">Hiển thị 1-25 của 25 sự kiện</div><div class="grow"></div><div class="btn">‹</div><div class="btn pri">1</div><div class="btn">›</div></div></div></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Bảng thật (<code>ui/monitoring_tab.py:_EventTable</code>) gộp cả 4 loại sự kiện (tool_call/mcp_call/security_block/permission) vào tab này nhưng không có cột phân loại — phải tự suy ra loại hành động từ cột "Tên".</li><li>Bộ lọc thật (<code>_wrap_with_filter</code>) chỉ có 1 ô tìm + nút ✨AI; 3 dropdown Loại/Trạng thái/Thời gian, 4 thẻ KPI, phân trang và nút Xuất CSV trong <code>12.ui-redesign-action-logs.html</code> đều là <b>tính năng mới</b>, chưa có trong code.</li><li>Bảng thật giới hạn ngầm <code>_MAX_ROWS</code> dòng mới nhất và không phân trang — không biết còn bao nhiêu sự kiện bị ẩn.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Thêm cột <b>Loại</b> dạng pill màu (Công cụ/Gọi MCP/Chặn bảo mật/Quyền) trước cột Hành động, tái dùng đúng bảng màu <code>.pill</code> đã áp cho Sự kiện bảo mật (mục 10).</li><li><span class="bad">Vượt phạm vi "chỉ sắp xếp lại"</span>: 4 thẻ KPI, 3 dropdown lọc, phân trang và nút Xuất CSV cần bổ sung logic đếm/lọc/phân trang/export ở <code>ui/monitoring_tab.py</code> trước khi hiện thực — hiện bảng thật chỉ lọc bằng 1 ô tìm text.</li></ul></div>\n</div></div>',
|
||
'monitoring-trạng-thái-agent': '<div class="bd">\n<p class="lead">Agent nào đang bật và nguồn định nghĩa.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab on">Agent</div><div class="tab">Agents Admin</div><div class="tab">Công cụ</div><div class="tab">Icon</div></div><div class="c grow"><div class="r tb"><div class="ttl">Trạng thái Agent</div><div class="grow"></div><div class="btn">⟳ Làm mới</div></div><div class="tblwrap grow"><table class="evtbl"><thead><tr><th>Agent</th><th>Trạng thái</th><th>Nguồn</th></tr></thead><tbody><tr><td><span class="ic blue" style="display:inline-flex;vertical-align:middle;margin-right:6px">👤</span>Cowork Agent</td><td><span class="pill gry">● Rảnh</span></td><td class="dt">Lượt đang chạy của tab Cowork</td></tr><tr><td><span class="ic amb" style="display:inline-flex;vertical-align:middle;margin-right:6px">⏱</span>Task Agent</td><td><span class="pill gry">● Rảnh</span></td><td class="dt">Task đang chạy trong Schedule Task</td></tr><tr><td><span class="ic pur" style="display:inline-flex;vertical-align:middle;margin-right:6px">◈</span>Knowledge Agent</td><td><span class="pill gry">● Rảnh</span></td><td class="dt">Ô hỏi của GraphRAG</td></tr><tr><td><span class="ic gry" style="display:inline-flex;vertical-align:middle;margin-right:6px">▦</span>Planner Agent</td><td><span class="pill gry">—</span></td><td class="dt">Một giai đoạn trong lượt Cowork/Task đang chạy (update_plan) — không theo dõi riêng</td></tr><tr><td><span class="ic gry" style="display:inline-flex;vertical-align:middle;margin-right:6px">⬡</span>Reasoning Agent</td><td><span class="pill gry">—</span></td><td class="dt">Luồng suy luận (reasoning) của model trong lượt đang chạy — không theo dõi riêng</td></tr><tr><td><span class="ic red" style="display:inline-flex;vertical-align:middle;margin-right:6px">🛡</span>Security Agent</td><td><span class="pill grn">● Bật</span></td><td class="dt">Kiểm duyệt prompt/đính kèm/lệnh của Agent Security — chạy inline trong lượt đang chạy</td></tr></tbody></table></div></div></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Bảng thật 3 cột (Agent · Đang chạy · Nguồn, <code>ui/monitoring_tab.py:_refresh_agent_status</code>) chỉ dùng chữ/icon đơn cho trạng thái — khó quét nhanh dòng nào đang chạy khi bảng dài.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Giữ nguyên 3 cột <b>Agent · Trạng thái · Nguồn</b> (không chuyển sang lưới thẻ, không thêm cột mới) — chỉ thêm icon màu theo loại agent trước tên và badge màu cho Trạng thái (xanh khi đang chạy/bật, xám khi "—") thay cho chữ thuần.</li></ul></div>\n</div></div>',
|
||
'monitoring-agents-admin': '<div class="bd">\n<p class="lead">Quản trị agent hệ thống. Cũng là nơi chọn model cho robot trợ giúp.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>Nút Kiểm tra</b>: probe provider thật</p>\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab on">Agents Admin</div><div class="tab">Công cụ</div><div class="tab">Icon</div></div><div class="c grow"><div class="r tb"><div class="ttl">Agents Admin</div><div class="grow"></div><div class="btn">⟳ Làm mới</div><div class="btn pri">+ Thêm</div></div><div class="s">Agent quản lý hệ thống, dùng chung mọi máy (lưu trong thư mục dùng chung): agent trợ giúp và agent chạy Schedule Task. Đây <b>KHÔNG</b> phải agent để chọn trong Cowork hay Co4E.</div><div class="tblwrap grow"><table class="evtbl"><thead><tr><th>Tên</th><th>Vai trò</th><th>Model</th><th>Kích hoạt</th><th>Trạng thái</th><th>Cập nhật</th><th></th></tr></thead><tbody><tr><td><span class="av red">SA</span>Security Agent</td><td><span class="pill red">Bảo mật</span></td><td class="dt">Ollama — qwen2.5:7b</td><td><span class="tsw on"><i></i></span></td><td><span class="pill grn">OK</span></td><td class="dt">11/08 09:30</td><td>✎ 🗑</td></tr><tr><td><span class="av pur">GA</span>GraphRAG Agent</td><td><span class="pill pur">Tri thức</span></td><td class="dt">Ollama — qwen2.5:14b</td><td><span class="tsw on"><i></i></span></td><td><span class="pill grn">OK</span></td><td class="dt">10/08 14:22</td><td>✎ 🗑</td></tr><tr><td><span class="av amb">MA</span>Monitor Agent</td><td><span class="pill amb">Giám sát</span></td><td class="dt">Mặc định — qwen2.5:7b</td><td><span class="tsw on"><i></i></span></td><td><span class="pill amb">Kiểm tra…</span></td><td class="dt">09/08 11:05</td><td>✎ 🗑</td></tr><tr><td><span class="av teal">HA</span>Help Assistant</td><td><span class="pill teal">Hỗ trợ</span></td><td class="dt">Mặc định — qwen2.5:7b</td><td><span class="tsw"><i></i></span></td><td><span class="pill gry">Chưa kiểm tra</span></td><td class="dt">08/08 16:40</td><td>✎ 🗑</td></tr></tbody></table></div></div></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n{{CONTROLS}}\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Cột Vai trò/Kích hoạt/Trạng thái chỉ là chữ hoặc icon đơn — khó phân biệt nhanh giữa các dòng khi bảng dài.</li><li>Bỏ [Kiểm tra tất cả] khỏi thanh công cụ chính làm mất lối vào hành động thật (<code>_check_all</code> trong <code>ui/agents_admin_tab.py</code>) — cần chỗ khác để gọi (icon riêng theo dòng, hoặc menu ⋯).</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Vai trò/Trạng thái chuyển sang badge màu + avatar viết tắt tên trước Tên agent; nút Sửa/Xoá dời vào từng dòng thay vì thanh công cụ rời bên dưới.</li><li>Thanh công cụ chính chỉ còn 2 nút: <b>Làm mới</b> (giống nút <code>monitoring.refresh</code> toàn màn hình) và <b>+ Thêm</b> (giống nút <code>agents_admin.add_btn</code> thật) — Sửa/Xoá đã dời vào từng dòng nên không cần ở đây nữa.</li></ul></div>\n</div></div>',
|
||
'monitoring-công-cụ': '<div class="bd">\n<p class="lead">Bật/tắt công cụ dựng sẵn và khai báo kết nối ngoài. Màn <b>duy nhất</b> còn hiện dải tab bên trong.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>Tool</b>: công cụ dựng sẵn + tự kiểm tra Internet · <b>Connector</b>: MCP · REST · MS365 · Jira</p>\n<div class="cap">Đề xuất — bố cục mới</div><div class="cap" style="margin:0 0 3px">Tab Tool</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab on">Công cụ</div><div class="tab">Icon</div></div><div class="r tb"><div class="tab on">Tool</div><div class="tab">Connector</div><div class="grow"></div></div><div class="c grow pane"><div class="r wrap"><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic blue">📄</div><b>read_file</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Đọc nội dung file text trong thư mục làm việc</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic blue">📁</div><b>list_dir</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Liệt kê file/thư mục con tại một đường dẫn</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic blue">✎</div><b>write_file</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Tạo file mới hoặc ghi đè toàn bộ file</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic blue">✏</div><b>edit_file</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Sửa một đoạn chính xác trong file có sẵn</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic grn">▤</div><b>run_command</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Chạy lệnh shell trong thư mục làm việc</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic pur">⭳</div><b>install_package</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Cài package Python (pip) vào môi trường app</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic amb">⤓</div><b>fetch_url</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Lấy nội dung trang web/tài liệu theo URL</span><div class="r tb" style="margin-top:3px"><div class="btn" id="fu-test">🌐 Kiểm tra Internet</div><span class="s" id="fu-status" style="color:var(--ok);margin-left:6px">✓ Kết nối OK · 42ms</span></div></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic pur">🔍</div><b>jira_search</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Tìm issue Jira bằng JQL, trả về danh sách tóm tắt</span></div><div class="card" style="flex:0 0 190px"><div class="r tb"><div class="ic pur">🔗</div><b>jira_get_issue</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Đọc chi tiết 1 issue Jira theo mã (vd ABX-123)</span></div></div><div class="grow"></div></div></div></div>\n<script>\n(function(){\n var btn=document.getElementById(\'fu-test\');\n if(!btn)return;\n btn.addEventListener(\'click\',function(){\n var st=document.getElementById(\'fu-status\');\n st.style.color=\'var(--fnt)\';\n st.textContent=\'Đang kiểm tra Internet…\';\n setTimeout(function(){\n st.style.color=\'var(--ok)\';\n st.textContent=\'✓ Kết nối OK · \'+(30+Math.floor(Math.random()*40))+\'ms\';\n },700);\n });\n})();\n</script>\n<div class="cap" style="margin:10px 0 3px">Tab Connector</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab on">Công cụ</div><div class="tab">Icon</div></div><div class="r tb"><div class="tab">Tool</div><div class="tab on">Connector</div><div class="grow"></div></div><div class="c grow pane"><div class="r tb"><span class="tsw on"><i></i></span><span class="lbl">Kết nối tới connector bên ngoài</span></div><div class="s">Một nơi duy nhất cho mọi nguồn tool ngoài — nhóm theo CAD (NX/CATIA/SolidWorks/AutoCAD), CAE (ANSA/ABAQUS/HyperWorks/ANSYS), MS365 (Microsoft 365/OneDrive/SharePoint) và Other (MCP server bất kỳ). MS365 tự kết nối qua server tích hợp sau khi đăng nhập; còn lại bạn trỏ mỗi connector tới MCP server bạn đã có hoặc REST API nó cung cấp (không kèm SDK hãng nào).</div><div class="grow" style="overflow-y:auto"><div class="r tb" style="gap:6px;margin-top:4px"><span>🔧</span><b>CAD</b><span class="lbl">(NX / CATIA / SolidWorks / AutoCAD)</span></div><div class="r wrap" style="margin-left:18px"><div class="card" style="flex:0 0 auto"><div class="r tb"><b>AutoCAD</b><span class="grow"></span><span class="tsw"><i></i></span></div><span class="s">MCP server (stdio)</span><span class="s" style="margin-top:2px">✎ Sửa · 🗑 Xóa</span></div></div><div class="r tb" style="gap:6px;margin-top:4px"><span>📐</span><b>CAE</b><span class="lbl">(ANSA / ABAQUS / HyperWorks / ANSYS)</span></div><div class="r wrap" style="margin-left:18px"><div class="card" style="flex:0 0 auto"><div class="r tb"><b>ANSA</b><span class="grow"></span><span class="tsw"><i></i></span></div><span class="s">MCP server (stdio)</span><span class="s" style="margin-top:2px">✎ Sửa · 🗑 Xóa</span></div></div><div class="r tb" style="gap:6px;margin-top:4px"><span>☁</span><b>MS365</b><span class="lbl">(Microsoft 365 / OneDrive / SharePoint)</span></div><div class="r wrap" style="margin-left:18px"><div class="card" style="flex:0 0 auto"><div class="r tb"><b>OneDrive</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Tích hợp, tự kết nối</span></div><div class="card" style="flex:0 0 auto"><div class="r tb"><b>SharePoint</b><span class="grow"></span><span class="tsw on"><i></i></span></div><span class="s">Tích hợp, tự kết nối</span></div></div><div class="r tb" style="gap:6px;margin-top:4px"><span>🔌</span><b>Other</b><span class="lbl">(any generic MCP server)</span></div><div class="r wrap" style="margin-left:18px"><div class="card" style="flex:0 0 auto"><div class="r tb"><b>Jira</b><span class="grow"></span><span class="tsw"><i></i></span></div><span class="s">Tích hợp, tự kết nối · chưa cấu hình</span><span class="s" style="margin-top:2px">✎ Sửa</span></div></div></div><div class="r tb" style="margin-top:4px"><div class="btn pri">+ Thêm connector…</div></div></div></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n{{CONTROLS}}\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Màn <b>duy nhất còn hiện dải tab</b> — 7 màn Monitoring kia bị ẩn. Không nhất quán.</li><li>Tab <b>Tool</b>/<b>Connector</b> lọt thỏm trong một mục nav.</li><li>Cấu hình kết nối tách khỏi Settings → thiết lập ở 2 nơi.</li><li>Tab <b>Tool</b> liệt kê <b>9 tool thật</b> (<code>core/tools.py:TOOL_SPECS</code>) dạng chữ phẳng (☑/☐) — không thấy ngay tool nào đang bật khi lướt nhanh.</li><li>Tab <b>Connector</b> là cây phân cấp 4 nhóm (CAD/CAE/MS365/Other, <code>ui/connectors_panel.py</code>) — phải bung từng nhóm mới thấy có gì bên trong.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Bỏ ẩn dải tab cho toàn bộ Monitoring → 8 tab một hàng; Tool/Connector ngang hàng.</li><li>Tab Tool: 9 tool thành <b>lưới thẻ căn trái</b> (không kéo giãn lấp đầy hàng) — icon màu theo loại + công tắc gạt bật/tắt, thay ô tick trong list phẳng.</li><li>Tab Connector: 4 nhóm thật thành khối <b>nhóm theo catalog</b> (không gộp vào tab Tool) — mỗi catalog là 1 tiêu đề (icon + tên + loại máy/phần mềm), bên dưới là hàng thẻ nhỏ căn trái, mỗi thẻ 1 option thật kèm <b>công tắc gạt</b> bật/tắt (không phải badge tĩnh) — đúng bản chất mỗi option đều chuyển được trạng thái, nhất quán với công tắc ở tab Tool; giữ đúng cấu trúc phân cấp 2 tầng của cây thật thay vì gộp phẳng vào 1 thẻ/catalog. Công tắc "Kết nối ngoài" tổng vẫn ở trên cùng. Thẻ của connector do người dùng tự thêm (AutoCAD, ANSA) có thêm ✎ Sửa/🗑 Xóa đúng như <code>_ext_edit</code>/<code>_ext_delete</code> thật; Jira (built-in) chỉ có ✎ Sửa (mở dialog cấu hình riêng, không xóa được); OneDrive/SharePoint (built-in MS365) không có nút nào — thật cũng chỉ bật/tắt, không sửa/xóa.</li><li>Nút <b>Kiểm tra Internet</b> dời từ thanh trên (tách khỏi tool nào) vào đúng bên trong thẻ <b>fetch_url</b>, khớp <code>tools_admin_tab.py:_fetch_url_desc_cell</code> — nút này gắn với khả năng fetch_url, không phải một hành động chung của cả tab.</li></ul></div>\n</div></div>',
|
||
'monitoring-icon': '<div class="bd">\n<p class="lead">Thư viện icon, dùng lại khi đặt icon cho agent Co4E.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf"><div class="rail"><div class="menutog"><span>MENU</span><span class="chev">‹</span></div><div class="rpick"><span>📁 Báo cáo tài chính Q3</span><span class="cv">▾</span></div><div class="newbtn">+ Đoạn chat mới</div><div class="i">Project</div><div class="i">Cowork</div><div class="i">Co4E</div><div class="i">Folder</div><div class="i">GraphRAG</div><div class="i">Schedule Task</div><div class="sep"></div><div class="hd">RECENTS</div><div class="scope">📁 Báo cáo tài chính Q3</div><div class="i sm">📌 Gom số liệu doanh thu</div><div class="i sm">Dựng slide trình bày Q3</div><div class="i sm allp">Tất cả project…</div><div class="grow"></div><div class="sep"></div><div class="i">Dashboard</div><div class="i">Monitoring</div><div class="acct">👤 local · Ollama ▾</div></div><div class="main"><div class="ttl">Monitoring</div><div class="r tb"><div class="tab">Tổng quan</div><div class="tab">Bảo mật</div><div class="tab">MCP</div><div class="tab">Hành động</div><div class="tab">Agent</div><div class="tab">Agents Admin</div><div class="tab">Công cụ</div><div class="tab on">Icon</div></div><div class="c grow"><div class="r tb"><div class="ttl">Icon</div><div class="grow"></div><div class="btn">+ Thêm icon</div><div class="btn">Dán SVG</div><div class="btn">Xoá</div></div><div class="srchwrap"><div class="inp grow">🔍 Tìm icon theo tên…</div></div><div class="hd2">ICON TÍCH HỢP</div><div class="r wrap"><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">✛</div><span class="s">plus</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">✓</div><span class="s">check</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">✕</div><span class="s">close</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">✎</div><span class="s">edit</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🗑</div><span class="s">trash</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">⟳</div><span class="s">refresh</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🔍</div><span class="s">search</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">⚙</div><span class="s">settings</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🤖</div><span class="s">robot</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🛡</div><span class="s">shield</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🔧</div><span class="s">wrench</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">★</div><span class="s">star</span></div></div><div class="hd2" style="margin-top:4px">ICON TÙY CHỈNH</div><div class="r wrap"><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">🧠</div><span class="s">brain</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">⌥</div><span class="s">code</span></div><div class="card" style="flex:0 0 56px;text-align:center;padding:6px 2px"><div style="font-size:16px">☁</div><span class="s">cloud</span></div></div></div></div><div class="dock fab" title="AI Assistant — trợ lý cách dùng app"><span class="spark">✨</span></div></div>\n{{CONTROLS}}\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Ô icon trong lưới hiện tại không có viền/hover rõ khi rê chuột hay khi đang chọn.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Ô tìm kiếm thêm icon kính lúp bên trái; mỗi ô icon có viền accent khi hover/chọn — cùng ngôn ngữ thẻ với Agent/Công cụ.</li></ul></div>\n</div></div>',
|
||
'dialog-settings': '<div class="bd">\n<p class="lead">Thiết lập toàn app. Cuộn dọc, không mục lục.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>5 nhóm</b>: Ngôn ngữ · Provider · Bảo mật (khoá mật khẩu) · Tham số · Routing</p>\n<div class="cap">Đề xuất — bố cục mới</div><div class="wf" id="setwf"><div class="main dlg"><div class="ttl">Cài đặt</div><div class="r grow"><div class="c w26 pane"><div class="li on" id="setl-chung">Chung<span class="s">ngôn ngữ · giao diện · khay</span></div><div class="li" id="setl-provider">AI Provider<span class="s">Ollama · qwen2.5-coder</span></div><div class="li" id="setl-sandbox">Bảo mật sandbox<span class="s">🔒 cần mở khoá</span></div><div class="li" id="setl-param">Tham số<span class="s">đính kèm · GraphRAG · giới hạn</span></div><div class="li" id="setl-routing">Auto Model Routing<span class="s">đang Tắt</span></div><div class="grow"></div></div><div class="c grow"><div id="setp-chung"><div class="frow"><span class="lbl">Ngôn ngữ hiển thị</span><div class="grow"></div><div class="seg" id="set-lang"><span data-v="en">English</span><span class="on" data-v="vi">Tiếng Việt</span><span data-v="ja">日本語</span></div></div><div class="frow"><span class="lbl">Giao diện</span><div class="grow"></div><div class="seg" id="set-theme"><span data-v="light">Sáng</span><span class="on" data-v="system">Hệ thống</span><span data-v="dark">Tối</span></div></div><div class="frow"><span class="lbl">Giữ chạy nền trong khay hệ thống khi đóng</span><div class="grow"></div><div class="tsw on"><i></i></div></div><div class="frow"><span class="lbl">Hiện thông báo khay khi tác vụ xong hoặc lỗi</span><div class="grow"></div><div class="tsw on"><i></i></div></div></div><div id="setp-provider" class="hide"><div class="lbl">Nhà cung cấp AI</div><div class="inp">Ollama (local models)</div><div class="lbl">Base URL</div><div class="inp">http://localhost:11434</div><div class="lbl">API Key</div><div class="inp">••••••••</div><div class="lbl">Model</div><div class="inp">qwen2.5-coder:7b <span class="s">⭳ Tải · ⚗ Test kết nối</span></div></div><div id="setp-sandbox" class="hide"><div class="r tb"><div class="inp grow">Nhập mật khẩu…</div><div class="btn">Unlock</div><span class="pill red">🔒 Locked</span></div><div class="frow"><span class="lbl">Xác nhận trước khi Cowork chạy lệnh</span><div class="grow"></div><div class="tsw"><i></i></div></div><div class="frow"><span class="lbl">Chặn mạng cho lệnh do agent chạy</span><div class="grow"></div><div class="tsw on"><i></i></div></div><div class="frow"><span class="lbl">Enable Agent Security (kiểm tra lệnh)</span><div class="grow"></div><div class="tsw on"><i></i></div></div><div class="frow"><span class="lbl">AI check commands</span><div class="grow"></div><div class="tsw"><i></i></div></div></div><div id="setp-param" class="hide"><div class="card"><div class="cap">Đính kèm</div><div class="frow"><span class="lbl">Số tệp tối đa</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-files" data-d="-1">−</span><span class="sv" id="sp-files">20</span><span class="sb" data-t="sp-files" data-d="1">+</span></div><span class="s">tệp</span></div><div class="frow"><span class="lbl">Token tối đa mỗi tệp</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-tokens" data-d="-5">−</span><span class="sv" id="sp-tokens">500</span><span class="sb" data-t="sp-tokens" data-d="5">+</span></div><span class="s">nghìn</span></div></div><div class="card"><div class="cap">Cấu trúc & GraphRAG</div><div class="frow"><span class="lbl">Số node tối đa</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-nodes" data-d="-1">−</span><span class="sv" id="sp-nodes">500</span><span class="sb" data-t="sp-nodes" data-d="1">+</span></div><span class="s">node</span></div><div class="frow"><span class="lbl">Số cạnh tối đa</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-edges" data-d="-1">−</span><span class="sv" id="sp-edges">500</span><span class="sb" data-t="sp-edges" data-d="1">+</span></div><span class="s">cạnh</span></div></div><div class="card"><div class="cap">Giới hạn sandbox</div><div class="frow"><span class="lbl">CPU</span><div class="grow"></div><b>Không giới hạn</b></div><div class="frow"><span class="lbl">Bộ nhớ</span><div class="grow"></div><b>2.048 MB</b></div><div class="frow"><span class="lbl">Disk I/O</span><div class="grow"></div><b>2.048 MB</b></div></div></div><div id="setp-routing" class="hide"><div class="frow"><span class="lbl">Chế độ</span><div class="grow"></div><div class="seg" id="set-rmode"><span class="on" data-v="off">Tắt</span><span data-v="auto">Auto</span><span data-v="manual">Manual</span></div></div><div class="frow"><span class="lbl">Chính sách</span><div class="grow"></div><div class="seg" id="set-rpolicy"><span data-v="quality">Chất lượng</span><span data-v="cost">Chi phí</span><span data-v="latency">Độ trễ</span><span class="on" data-v="balanced">Cân bằng</span></div></div><div class="frow"><span class="lbl">Ngưỡng tăng điểm tối thiểu</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-mingain" data-d="-1">−</span><span class="sv" id="sp-mingain">5</span><span class="sb" data-t="sp-mingain" data-d="1">+</span></div><span class="s">%</span></div><div class="frow"><span class="lbl">Timeout xác nhận</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-timeout" data-d="-1">−</span><span class="sv" id="sp-timeout">60</span><span class="sb" data-t="sp-timeout" data-d="1">+</span></div><span class="s">giây</span></div><div class="frow"><span class="lbl">Chu kỳ đánh giá lại</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-interval" data-d="-1">−</span><span class="sv" id="sp-interval">24</span><span class="sb" data-t="sp-interval" data-d="1">+</span></div><span class="s">giờ</span></div><div class="frow"><span class="lbl">Đồng thời mỗi provider</span><div class="grow"></div><div class="stp"><span class="sb" data-t="sp-concurrency" data-d="-1">−</span><span class="sv" id="sp-concurrency">2</span><span class="sb" data-t="sp-concurrency" data-d="1">+</span></div></div><div class="lbl">Judge model</div><div class="inp">(để trống · dùng model đang chọn)</div><div class="r tb"><div class="btn">⟳ Đánh giá lại ngay</div></div></div><div class="grow"></div><div class="r tb end"><div class="btn">Huỷ</div><div class="btn pri">Lưu</div></div></div></div></div></div>\n<script>\n(function(){\n var panels=[\'chung\',\'provider\',\'sandbox\',\'param\',\'routing\'];\n panels.forEach(function(p){\n document.getElementById(\'setl-\'+p).addEventListener(\'click\',function(){\n panels.forEach(function(q){\n document.getElementById(\'setl-\'+q).classList.toggle(\'on\',q===p);\n document.getElementById(\'setp-\'+q).classList.toggle(\'hide\',q!==p);\n });\n });\n });\n Array.prototype.forEach.call(document.querySelectorAll(\'#setwf .tsw\'),function(t){\n t.addEventListener(\'click\',function(){t.classList.toggle(\'on\');});\n });\n Array.prototype.forEach.call(document.querySelectorAll(\'#setwf .seg\'),function(seg){\n Array.prototype.forEach.call(seg.querySelectorAll(\'span\'),function(s){\n s.addEventListener(\'click\',function(){\n Array.prototype.forEach.call(seg.querySelectorAll(\'span\'),function(x){x.classList.remove(\'on\');});\n s.classList.add(\'on\');\n });\n });\n });\n Array.prototype.forEach.call(document.querySelectorAll(\'#setwf .stp .sb\'),function(btn){\n btn.addEventListener(\'click\',function(){\n var target=document.getElementById(btn.dataset.t);\n var v=parseInt(target.textContent,10)+parseInt(btn.dataset.d,10);\n if(v<0)v=0;\n target.textContent=String(v);\n });\n });\n})();\n</script>\n{{CONTROLS}}\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li>Năm group cuộn dọc, không mục lục.</li><li>Sandbox khoá bằng <b>mật khẩu hard-code</b> (<code>settings_dialog.py:115</code>).</li><li>Provider/Ngôn ngữ/Giao diện ở top bar, tách khỏi Settings.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Thêm cột mục lục bên trái; gom Ngôn ngữ/Giao diện vào nhóm Chung (AI Provider vẫn là nhóm riêng như hiện tại, không gộp).</li><li>Đổi cách hiển thị field theo đúng loại dữ liệu: checkbox ☑/☐ → toggle switch, dropdown ít lựa chọn (2–4 giá trị) → segmented control, số nhập tay → stepper, 3 nhóm con trong Tham số → gom thành card — vẫn đúng field/giá trị mặc định thật từ <code>ui/settings_dialog.py</code>, chỉ đổi cách trình bày chứ không đổi dữ liệu.</li></ul></div>\n</div></div>',
|
||
'dialog-task-editor': '<div class="bd">\n<p class="lead">Khai báo tác vụ hẹn giờ: nội dung, lịch lặp, phụ thuộc, thông báo.</p>\n<div class="cap">Hiện tại</div>{{SHOT}}\n<p class="rg"><b>5 nhóm</b>: Cơ bản · Lịch · Đầu vào · Phụ thuộc · Thực thi</p>\n<div class="cap">Đề xuất — bố cục mới</div>\n<p class="mut">Cùng 1 dialog <code>TaskEditorDialog</code> cho cả <b>Thêm task</b> và <b>Sửa task</b> — chỉ đổi tiêu đề (Thêm/Sửa), bố cục dưới đây dùng chung cho cả hai. Layout theo đúng kiểu màn <b>Cài đặt</b>: danh sách 5 nhóm bên trái thay cho 3 tab wizard, đúng 5 <code>QGroupBox</code> thật (không phải 3 bước tự đặt ra).</p>\n<div class="wf" id="taskwf"><div class="main dlg"><div class="ttl">Sửa task</div><div class="r grow"><div class="c w26 pane"><div class="li on" id="tel-basic">Cơ bản<span class="s">tiêu đề · loại chạy · model</span></div><div class="li" id="tel-sched">Lịch<span class="s">chạy 1 lần · lặp lại</span></div><div class="li" id="tel-input">Đầu vào<span class="s">prompt · tệp · liên kết</span></div><div class="li" id="tel-dep">Phụ thuộc<span class="s">task kế tiếp · chờ hoàn tất</span></div><div class="li" id="tel-exec">Thực thi<span class="s">thử lại · timeout · phê duyệt</span></div><div class="grow"></div></div><div class="c grow"><div id="tep-basic"><div class="frow"><span class="lbl">Chế độ</span><div class="grow"></div><div class="seg" id="tsk-mode"><span class="on" data-v="normal">Bình thường</span><span data-v="automation">Tự động</span></div></div><div class="lbl">Tiêu đề</div><div class="inp">Gửi báo cáo doanh thu hằng ngày 08:00</div><div class="lbl">Mô tả</div><div class="inp tall">Gom số liệu ngày hôm trước, dựng bảng và gửi email cho nhóm kế toán. <span class="s">✨ Sinh prompt từ mô tả</span></div><div class="lbl">Project</div><div class="inp">Báo cáo tài chính Q3</div><div class="frow"><span class="lbl">Loại chạy</span><div class="grow"></div><div class="seg" id="tsk-runkind"><span class="on" data-v="agent">AI Agent</span><span data-v="flow">Co4E Flow</span></div></div><div class="lbl">Nhà cung cấp</div><div class="inp">Ollama (local models)</div><div class="lbl">Model</div><div class="inp">qwen2.5-coder:7b <span class="s">⭳ Tải model</span></div><div class="lbl">Skill</div><div class="inp">(Không dùng)</div><div class="lbl">Ưu tiên</div><div class="inp">medium</div><div class="lbl">Trạng thái</div><div class="inp">backlog</div></div><div id="tep-sched" class="hide"><div class="frow"><span class="lbl">Bật lịch chạy</span><div class="grow"></div><div class="tsw on"><i></i></div></div><div class="lbl">Thời điểm chạy</div><div class="inp">2026-08-17 08:00 AM</div><div class="lbl">Lặp lại</div><div class="inp">Hằng ngày</div><div class="lbl">Cron (khi lặp = tuỳ chỉnh)</div><div class="inp">0 8 * * * <span class="s">— chọn mẫu có sẵn</span></div><div class="frow"><span class="lbl">Chỉ ngày làm việc (bỏ T7/CN)</span><div class="grow"></div><div class="tsw"><i></i></div></div><div class="frow"><span class="lbl">Bỏ qua ngày nghỉ lễ</span><div class="grow"></div><div class="tsw on"><i></i></div></div><div class="lbl">Mã quốc gia lễ</div><div class="inp">VN</div><div class="frow"><span class="lbl">Kênh thông báo</span><div class="grow"></div><div class="seg" id="tsk-notify"><span class="on" data-v="none">Không</span><span data-v="teams">Teams</span><span data-v="outlook">Outlook</span></div></div><div class="lbl">Email nhận thông báo</div><div class="inp">ketoan@company.com</div></div><div id="tep-input" class="hide"><div class="lbl">Prompt thủ công</div><div class="inp tall">Tổng hợp số liệu doanh thu ngày hôm trước từ file đính kèm, dựng bảng tóm tắt.</div><div class="lbl">Tệp đính kèm</div><div class="li">📄 sales_template.xlsx</div><div class="li">📄 Q3_report_outline.docx</div><div class="r tb"><div class="btn">+ Thêm tệp</div><div class="btn">🗑 Xoá</div></div><div class="lbl">Liên kết</div><div class="li">🔗 https://intranet.company.com/sales-dashboard</div><div class="r tb"><div class="btn">+ Thêm liên kết</div><div class="btn">🗑 Xoá</div></div></div><div id="tep-dep" class="hide"><div class="lbl">Task kế tiếp</div><div class="inp">(Không có)</div><div class="lbl">Chế độ chạy tiếp</div><div class="inp">Không tự động chạy tiếp</div><div class="frow"><span class="lbl">Dùng output làm input task sau</span><div class="grow"></div><div class="tsw"><i></i></div></div><div class="lbl">Chờ các task này xong (fan-in)</div><div class="li">☑ Gom số liệu doanh thu</div><div class="li">☐ Dựng slide trình bày Q3</div></div><div id="tep-exec" class="hide"><div class="lbl">Số lần thử lại</div><div class="inp">0 lần</div><div class="lbl">Timeout</div><div class="inp">600 giây</div><div class="frow"><span class="lbl">Cần phê duyệt (chờ bấm Chạy ngay)</span><div class="grow"></div><div class="tsw"><i></i></div></div></div><div class="grow"></div><div class="r tb end"><div class="btn">Huỷ</div><div class="btn pri">Lưu</div></div></div></div></div></div>\n<script>\n(function(){\n var panels=[\'basic\',\'sched\',\'input\',\'dep\',\'exec\'];\n panels.forEach(function(p){\n document.getElementById(\'tel-\'+p).addEventListener(\'click\',function(){\n panels.forEach(function(q){\n document.getElementById(\'tel-\'+q).classList.toggle(\'on\',q===p);\n document.getElementById(\'tep-\'+q).classList.toggle(\'hide\',q!==p);\n });\n });\n });\n Array.prototype.forEach.call(document.querySelectorAll(\'#taskwf .tsw\'),function(t){\n t.addEventListener(\'click\',function(){t.classList.toggle(\'on\');});\n });\n Array.prototype.forEach.call(document.querySelectorAll(\'#taskwf .seg\'),function(seg){\n Array.prototype.forEach.call(seg.querySelectorAll(\'span\'),function(s){\n s.addEventListener(\'click\',function(){\n Array.prototype.forEach.call(seg.querySelectorAll(\'span\'),function(x){x.classList.remove(\'on\');});\n s.classList.add(\'on\');\n });\n });\n });\n})();\n</script>\n{{CONTROLS}}\n<div class="cols pc">\n<div><div class="cap">Vấn đề</div><ul class="pr"><li><b>Năm group</b> dọc — form dài nhất app, không thấy đang ở bước nào.</li></ul></div>\n<div><div class="cap">Thay đổi</div><ul class="pr"><li>Đổi sang layout <b>danh sách bên trái + panel bên phải</b> giống màn Cài đặt (thay vì chia tab) — 5 mục danh sách khớp đúng 5 <code>QGroupBox</code> thật (<b>Cơ bản · Lịch · Đầu vào · Phụ thuộc · Thực thi</b>, xem <code>ui/task_editor_dialog.py</code>), luôn thấy đang ở nhóm nào và còn bao nhiêu nhóm nữa — nhất quán với cách điều hướng ở Cài đặt thay vì mỗi màn một kiểu.</li></ul></div>\n</div></div>',
|
||
}
|
||
|
||
EXTRA_CSS = '.embed{width:100%;height:760px;border:1px solid var(--bd);border-radius:var(--r);\nbackground:#fff;display:block}\np.hint{margin:4px 0 8px}\n.wf .acct{margin-top:6px;padding:6px 7px;border-top:1px solid var(--navb);color:var(--mut);font-size:10px}\npadding:6px 8px;color:var(--tx);height:26px;box-sizing:border-box;overflow:hidden}\n.wf .inp.tall{min-height:52px;height:auto}\npadding:4px 9px;white-space:nowrap;align-self:center;height:26px;box-sizing:border-box;\ndisplay:inline-flex;align-items:center;justify-content:center;line-height:1}\n/* ---- section-10 interactive-preview vocabulary: literal palette from 10SuKienBaoMat.html ---- */\n.wf .kpi2{flex:1;background:var(--rz);border:1px solid var(--bd);border-radius:6px;padding:7px 9px;display:flex;align-items:center;gap:7px;min-width:0}\n.wf .kpi2 b{font-size:15px;display:block;line-height:1.2}\n.wf .ic{width:20px;height:20px;border-radius:5px;flex:none;display:flex;align-items:center;justify-content:center;font-size:10px}\n.wf .ic.blue{background:#DEECF9;color:#0078D4}.wf .ic.grn{background:#DFF6DD;color:#107C10}\n.wf .ic.red{background:#FDE7E9;color:#D13438}.wf .ic.pur{background:#F3E8FD;color:#8764B8}\n.wf .ic.amb{background:#FFF4CE;color:#795548}.wf .ic.gry{background:#F3F2F1;color:#605E5C}\n.wf .pill{display:inline-block;padding:2px 8px;border-radius:99px;font-size:9px;font-weight:700;white-space:nowrap}\n.wf .pill.red{background:#FDE7E9;color:#D13438}.wf .pill.grn{background:#E4F7C7;color:#498205}\n.wf .pill.teal{background:#D2F0EE;color:#008272}.wf .pill.org{background:#FDE6D9;color:#DA3B01}\n.wf .pill.blue{background:#DEECF9;color:#0078D4}.wf .pill.amb{background:#FFF4CE;color:#795548}\n.wf .pill.pur{background:#F3E8FD;color:#8764B8}.wf .pill.gry{background:#F3F2F1;color:#605E5C}\n.wf .r.wrap{flex-wrap:wrap}\n.wf .av{display:inline-flex;width:16px;height:16px;border-radius:50%;flex:none;align-items:center;\njustify-content:center;font-size:7px;font-weight:700;color:#fff;margin-right:4px}\n.wf .av.red{background:#D13438}.wf .av.blue{background:#0078D4}\n.wf .av.pur{background:#8764B8}.wf .av.grn{background:#107C10}.wf .av.amb{background:#FFB900}\n.wf .av.teal{background:#008272}.wf .av.dark{background:#24292F}.wf .av.olv{background:#498205}\n.wf .tblwrap{overflow-y:auto;overflow-x:hidden}\n.wf .evtbl{width:100%;border-collapse:collapse;font-size:9.5px}\n.wf .evtbl thead{position:sticky;top:0;background:var(--bg)}\n.wf .evtbl th{text-align:left;padding:4px 6px;color:var(--fnt);font-weight:700;text-transform:uppercase;\nfont-size:8px;letter-spacing:.04em;border-bottom:1px solid var(--bd);white-space:nowrap;cursor:default}\n.wf .evtbl td{padding:4px 6px;border-bottom:1px solid var(--bd);white-space:nowrap;vertical-align:middle}\n.wf .evtbl td.dt{white-space:normal;color:var(--fnt)}\n.wf .evtbl tbody tr{cursor:pointer}.wf .evtbl tbody tr:hover{background:var(--sf)}\n.wf .pane.hide{display:none}\n.wf .hide{display:none}\n/* ---- Settings field-display alternatives (toggle switch / stepper) ---- */\n.wf .tsw{display:inline-flex;align-items:center;width:32px;height:17px;border-radius:99px;\nbackground:var(--bds);position:relative;cursor:pointer;flex:none;transition:background .15s}\n.wf .tsw i{position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;\nbackground:#fff;transition:left .15s;box-shadow:0 1px 2px rgba(0,0,0,.25)}\n.wf .tsw.on{background:var(--ac)}\n.wf .tsw.on i{left:17px}\n.wf .stp{display:inline-flex;align-items:center;border:1px solid var(--bds);border-radius:4px;\noverflow:hidden;height:26px;box-sizing:border-box;flex:none}\n.wf .stp .sb{width:22px;height:100%;display:flex;align-items:center;justify-content:center;\nbackground:var(--rz);cursor:pointer;font-weight:700;color:var(--tx);user-select:none}\n.wf .stp .sb:hover{background:var(--sf)}\n.wf .stp .sv{padding:0 10px;min-width:44px;text-align:center;font-weight:600;background:var(--bg);\nheight:100%;display:flex;align-items:center;justify-content:center;\nborder-left:1px solid var(--bds);border-right:1px solid var(--bds)}\n.wf .frow{display:flex;align-items:center;gap:6px;min-height:0;padding:2px 0}\n.wf .seg{display:inline-flex;border:1px solid var(--bds);border-radius:4px;overflow:hidden;flex:none}\n.wf .seg span{background:var(--bg);color:var(--mut);padding:3px 10px;cursor:pointer;font-size:10px;white-space:nowrap}\n.wf .seg span.on{background:var(--ac);color:#fff;font-weight:600}\n.wf .pane.overlay{position:absolute;top:0;right:0;bottom:0;width:38%;z-index:5;\nbackground:var(--bg);border-left:1px solid var(--bd);box-shadow:-6px 0 14px rgba(0,0,0,.18)}\n.wf .dtl{padding:2px 0 0}\n.wf .dtl.grow{overflow-y:auto}\n.wf .pnlfoot{border-top:1px solid var(--bd);flex:none;padding-top:6px}\n#s10close{cursor:pointer}\n#s11close{cursor:pointer}\n.wf .dtl .hd3{font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--fnt);\npadding-bottom:3px;margin:8px 0 3px;border-bottom:1px solid var(--bd)}\n.wf .dtl .hd3:first-child{margin-top:0}\n.wf .dtl .fld{display:flex;justify-content:space-between;align-items:center;padding:3px 0;gap:6px}\n.wf .dtl .fld .lbl{color:var(--mut)}\n.wf .dtl .fld .val{font-weight:600;text-align:right}\n.wf .dtl .mono{font-family:"Cascadia Code",Consolas,monospace;background:var(--sf);border:1px solid var(--bd);\nborder-radius:3px;padding:1px 6px;font-size:9px;font-weight:400}\n.wf .dtl .tagn{background:var(--sf);border-radius:3px;padding:1px 7px;font-size:9px;font-weight:400}\n.wf .dtl .code{background:#1b1a19;color:#CCFF00;font-family:"Cascadia Code",Consolas,monospace;\nfont-size:9px;padding:6px 8px;border-radius:4px;margin:4px 0;display:flex;align-items:center;\njustify-content:space-between;gap:6px}\n.wf .dtl .code .cpy{background:rgba(255,255,255,.15);color:#fff;border-radius:3px;padding:2px 6px;\nfont-size:8px;white-space:nowrap;flex:none;cursor:pointer}\n.wf select.btn{appearance:none;-webkit-appearance:none;font:inherit;color:inherit;padding-right:16px;cursor:pointer;\nbackground-image:url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'8\' height=\'8\' viewBox=\'0 0 10 10\'%3E%3Cpath d=\'M1 3.5L5 7.5L9 3.5\' stroke=\'%23888\' stroke-width=\'1.5\' fill=\'none\' stroke-linecap=\'round\'/%3E%3C/svg%3E");\nbackground-repeat:no-repeat;background-position:right 4px center}\n.wf input.inp{font:inherit;color:inherit;outline:none;width:100%}\n.wf .srchwrap{position:relative;display:flex;align-items:center;min-width:0}\n.wf .srchwrap .inp{padding-right:48px}\n.wf .srchwrap .aibtn{position:absolute;right:3px;top:50%;transform:translateY(-50%);cursor:pointer;\nline-height:1;padding:5px 10px;border-radius:4px;font-size:11px}\n.wf .edge{background:var(--sf);border:1px solid var(--bds);border-right:none;border-radius:5px 0 0 5px;padding:14px 5px;color:var(--mut)}\n.wf .aibadge{background:#E6F6F4;border:1px solid #7FD0C4;border-radius:6px;padding:7px 11px;font-weight:700;color:#0F6E62;white-space:nowrap}\n.wf .dock.badge{background:#E6F6F4;border:1px solid #7FD0C4;border-radius:6px;padding:7px 11px;font-weight:700;color:#0F6E62;white-space:nowrap}\n.wf .dock.pnl{width:74%;height:76%;background:var(--sf);border:1px solid var(--bds);border-radius:6px;box-shadow:0 3px 10px rgba(16,32,64,.13)}\n.wf .edge{background:var(--sf);border:1px solid var(--bds);border-right:none;border-radius:5px 0 0 5px;padding:14px 5px;color:var(--mut)}\n.wf .aibadge{background:#E6F6F4;border:1px solid #7FD0C4;border-radius:6px;padding:7px 11px;font-weight:700;color:#0F6E62;white-space:nowrap}\n.wf .dock .badge{background:#E6F6F4;border:1px solid #7FD0C4;border-radius:6px;\n/* Menu ⋯ trong panel tro ly — ghep tu ui-audit.html */\n/* Chấm trợ lý 26px — ghép từ ui-audit.html */'
|
||
|
||
EXTRA_JS = [
|
||
]
|