From dc6cb309c210b28070903ddbe0c80b0cb2f2b948 Mon Sep 17 00:00:00 2001 From: NamPDT Date: Mon, 17 Aug 2026 16:15:49 +0900 Subject: [PATCH] fix(monitoring): match the wording and the figures the wireframe actually shows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading the page's Overview line by line against the app turned up more than layout: * Tab strip: "Sự kiện bảo mật / Lịch sử gọi MCP / Nhật ký hành động / Trạng thái Agent" → "Bảo mật / MCP / Hành động / Agent", as drawn. The long names are also what pushed "Icon" off a 1024px window behind scroll arrows; all eight now fit. * Headings: "SỬ DỤNG TOKEN & CHI PHÍ" → "TOKEN & CHI PHÍ", "SỬ DỤNG TÀI NGUYÊN" → "TÀI NGUYÊN", "CHI TIẾT SANDBOX" → "SANDBOX & QUYỀN", "HOẠT ĐỘNG GẦN ĐÂY" → "NHẬT KÝ GẦN ĐÂY". * Tiles put the number FIRST and its name under it, which is how the page draws them; "Tổng chi phí" → "Chi phí" and Budget → "Ngân sách" in Vietnamese. Applies to the Dashboard's cards too, which share the widget. * Resources showed I/O and network RATES; the drawing shows capacity — memory as used/total (138 MB/15 GB) and the workspace drive's free space (15 GB trống). The rates are still measured and kept. * "SANDBOX & QUYỀN" rendered as "SANDBOX _QUYỀN": a group-box title treats "&" as a mnemonic. Same bug as the usage title, now fixed in both. Co-Authored-By: Claude Opus 5 (1M context) --- i18n.py | 25 +++++++++++++++---------- ui/monitoring_tab.py | 25 +++++++++++++++++++++---- ui/widgets.py | 7 +++++-- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/i18n.py b/i18n.py index 416825f..6adb66b 100644 --- a/i18n.py +++ b/i18n.py @@ -1274,7 +1274,7 @@ STRINGS: Dict[str, Dict[str, str]] = { "dashboard.card_in": {"en": "Input", "ja": "入力", "vi": "Input"}, "dashboard.card_out": {"en": "Output", "ja": "出力", "vi": "Output"}, "dashboard.card_cache": {"en": "Cache", "ja": "キャッシュ", "vi": "Cache"}, - "dashboard.card_cost": {"en": "Total cost", "ja": "合計コスト", "vi": "Tổng chi phí"}, + "dashboard.card_cost": {"en": "Cost", "ja": "コスト", "vi": "Chi phí"}, "dashboard.card_turns": {"en": "{n} turns", "ja": "{n} ターン", "vi": "{n} lượt"}, "dashboard.prices_label": { "en": "Unit price (USD / 1M tokens):", "ja": "単価 (USD / 100万トークン):", @@ -1309,7 +1309,7 @@ STRINGS: Dict[str, Dict[str, str]] = { "dashboard.ref_last_week": {"en": "Last week", "ja": "先週", "vi": "Tuần trước"}, "dashboard.ref_last_month": {"en": "Last month", "ja": "先月", "vi": "Tháng trước"}, "dashboard.ref_last_year": {"en": "Last year", "ja": "昨年", "vi": "Năm trước"}, - "usage.budget_title": {"en": "Budget", "ja": "予算", "vi": "Budget"}, + "usage.budget_title": {"en": "Budget", "ja": "予算", "vi": "Ngân sách"}, "usage.budget_no_budget": {"en": "No budget set", "ja": "予算未設定", "vi": "Chưa đặt Budget"}, "usage.budget_used_pct": {"en": "{pct}% used", "ja": "{pct}% 使用済み", "vi": "Đã dùng {pct}%"}, "usage.budget_over_warning": {"en": "⚠ Over 85% of budget used", @@ -2374,10 +2374,10 @@ STRINGS: Dict[str, Dict[str, str]] = { # ---- monitoring_tab.py (📊 Monitoring Dashboard) -------------------- "monitoring.title": {"en": "Monitoring Dashboard", "ja": "モニタリングダッシュボード", "vi": "Bảng giám sát"}, "monitoring.refresh": {"en": "Refresh", "ja": "更新", "vi": "Làm mới"}, - "monitoring.tab_security": {"en": "Security Events", "ja": "セキュリティイベント", "vi": "Sự kiện bảo mật"}, - "monitoring.tab_mcp": {"en": "MCP Call History", "ja": "MCP 呼び出し履歴", "vi": "Lịch sử gọi MCP"}, - "monitoring.tab_actions": {"en": "Action Logs", "ja": "アクションログ", "vi": "Nhật ký hành động"}, - "monitoring.tab_agents": {"en": "Agent Status", "ja": "エージェント状態", "vi": "Trạng thái Agent"}, + "monitoring.tab_security": {"en": "Security", "ja": "セキュリティ", "vi": "Bảo mật"}, + "monitoring.tab_mcp": {"en": "MCP", "ja": "MCP", "vi": "MCP"}, + "monitoring.tab_actions": {"en": "Actions", "ja": "アクション", "vi": "Hành động"}, + "monitoring.tab_agents": {"en": "Agent", "ja": "エージェント", "vi": "Agent"}, "monitoring.tab_accounts": {"en": "Accounts", "ja": "アカウント", "vi": "Tài khoản"}, "monitoring.col_time": {"en": "Time", "ja": "時刻", "vi": "Thời gian"}, "monitoring.col_role": {"en": "Agent Role", "ja": "エージェント役割", "vi": "Vai trò Agent"}, @@ -2390,6 +2390,9 @@ STRINGS: Dict[str, Dict[str, str]] = { "monitoring.overview_calls": {"en": "Calls", "ja": "呼び出し", "vi": "Lượt gọi"}, # The fold under the Sandbox summary line — the wireframe shows only the # summary, so the ID / created / uptime / limits rows live behind this. + "monitoring.overview_disk_free": { + "en": "{size} free", "ja": "空き {size}", "vi": "{size} trống"}, + "monitoring.overview_disk_label": {"en": "Disk", "ja": "ディスク", "vi": "Đĩa"}, "monitoring.overview_sbx_detail": { "en": "Details", "ja": "詳細", "vi": "Chi tiết"}, "monitoring.col_detail": {"en": "Detail", "ja": "詳細", "vi": "Chi tiết"}, @@ -2429,7 +2432,7 @@ STRINGS: Dict[str, Dict[str, str]] = { # ---- monitoring_tab.py — Overview card dashboard --------------------- "monitoring.tab_overview": {"en": "Overview", "ja": "概要", "vi": "Tổng quan"}, "monitoring.overview_usage_title": { - "en": "Token Usage & Cost", "ja": "トークン使用量とコスト", "vi": "Sử dụng token & Chi phí"}, + "en": "Token & Cost", "ja": "トークンとコスト", "vi": "Token & Chi phí"}, "monitoring.overview_currency": {"en": "Currency:", "ja": "通貨:", "vi": "Tiền tệ:"}, "monitoring.tab_agents_admin": { "en": "Agents Admin", "ja": "エージェント管理", "vi": "Agents Admin"}, @@ -2894,11 +2897,11 @@ STRINGS: Dict[str, Dict[str, str]] = { "ja": "質問をAIがフィルターキーワードに変換します。", "vi": "AI chuyển câu hỏi thành từ khóa lọc (vd: \"hôm nay lệnh nào bị lỗi?\")."}, "monitoring.overview_activity_title": { - "en": "Recent Activity", "ja": "最近のアクティビティ", "vi": "Hoạt động gần đây"}, + "en": "Recent log", "ja": "最近のログ", "vi": "Nhật ký gần đây"}, "monitoring.overview_no_activity": { "en": "No activity yet.", "ja": "まだアクティビティはありません。", "vi": "Chưa có hoạt động nào."}, "monitoring.overview_resource_title": { - "en": "Resource Usage", "ja": "リソース使用状況", "vi": "Sử dụng tài nguyên"}, + "en": "Resources", "ja": "リソース", "vi": "Tài nguyên"}, "monitoring.overview_res_cpu": {"en": "CPU", "ja": "CPU", "vi": "CPU"}, "monitoring.overview_res_mem": {"en": "Memory", "ja": "メモリ", "vi": "Bộ nhớ"}, "monitoring.overview_res_disk": {"en": "Disk I/O", "ja": "ディスク I/O", "vi": "Disk I/O"}, @@ -2925,7 +2928,9 @@ STRINGS: Dict[str, Dict[str, str]] = { "monitoring.pricing_col_input": {"en": "Input price", "ja": "入力単価", "vi": "Giá input"}, "monitoring.pricing_col_output": {"en": "Output price", "ja": "出力単価", "vi": "Giá output"}, "monitoring.overview_sandbox_details_title": { - "en": "Sandbox Details", "ja": "サンドボックス詳細", "vi": "Chi tiết Sandbox"}, + # One section now, holding both the sandbox facts and the permissions. + "en": "Sandbox & Permissions", "ja": "サンドボックスと権限", + "vi": "Sandbox & Quyền"}, "monitoring.overview_sandbox_id": {"en": "Sandbox ID", "ja": "サンドボックス ID", "vi": "Sandbox ID"}, "monitoring.overview_status": {"en": "Status", "ja": "状態", "vi": "Trạng thái"}, "monitoring.overview_status_running": {"en": "Running", "ja": "実行中", "vi": "Đang chạy"}, diff --git a/ui/monitoring_tab.py b/ui/monitoring_tab.py index 48529a0..e9a037e 100644 --- a/ui/monitoring_tab.py +++ b/ui/monitoring_tab.py @@ -530,8 +530,11 @@ class MonitoringTab(QWidget): self.ov_cpu_lbl, self.ov_cpu_bar, self.ov_cpu_val = _bar_row() self.ov_mem_lbl, self.ov_mem_bar, self.ov_mem_val = _bar_row() - self.ov_disk_lbl, self.ov_disk_val = _text_row() - self.ov_network_lbl, self.ov_network_val = _text_row() + self.ov_diskfree_lbl, self.ov_diskfree_val = _text_row() + # I/O and network rates keep working; they are read from the detail + # fold rather than the summary line the wireframe draws. + self.ov_disk_lbl, self.ov_disk_val = QLabel(), QLabel() + self.ov_network_lbl, self.ov_network_val = QLabel(), QLabel() res_lay.addStretch(1) # ---- Model pricing (beside the CPU/resource group) ------------------ @@ -730,6 +733,7 @@ class MonitoringTab(QWidget): self.action_page.filter_edit.setPlaceholderText(tr("monitoring.filter_placeholder")) self.ov_cpu_lbl.setText(tr("monitoring.overview_res_cpu")) self.ov_mem_lbl.setText(tr("monitoring.overview_res_mem")) + self.ov_diskfree_lbl.setText(tr("monitoring.overview_disk_label")) self.ov_disk_lbl.setText(tr("monitoring.overview_res_disk")) self.ov_network_lbl.setText(tr("monitoring.overview_res_network")) # model pricing panel @@ -745,7 +749,9 @@ class MonitoringTab(QWidget): tr("monitoring.pricing_col_maxout"), tr("monitoring.pricing_col_input"), tr("monitoring.pricing_col_output")]) - self.ov_sandbox_details_group.setTitle(tr("monitoring.overview_sandbox_details_title").upper()) + self.ov_sandbox_details_group.setTitle( + # "&" is a mnemonic marker in a group-box title — double it. + tr("monitoring.overview_sandbox_details_title").upper().replace("&", "&&")) self.ov_sbx_id_lbl.setText(tr("monitoring.overview_sandbox_id")) self.ov_sbx_status_lbl.setText(tr("monitoring.overview_status")) self.ov_sbx_created_lbl.setText(tr("monitoring.overview_created")) @@ -809,7 +815,18 @@ class MonitoringTab(QWidget): except Exception: mem_pct = 0 self.ov_mem_bar.setValue(min(mem_pct, 100)) - self.ov_mem_val.setText(_fmt_bytes(own_mem)) + try: + self.ov_mem_val.setText(f"{_fmt_bytes(own_mem)}/{_fmt_bytes(total_mem)}") + except Exception: # noqa: BLE001 + self.ov_mem_val.setText(_fmt_bytes(own_mem)) + # Free disk on the workspace drive — a capacity fact, unlike the I/O + # rate that used to sit here, and the one the drawing shows. + try: + free = psutil.disk_usage(str(self.ctx.config.cowork_output_dir())).free + self.ov_diskfree_val.setText( + tr("monitoring.overview_disk_free", size=_fmt_bytes(free))) + except Exception: # noqa: BLE001 + self.ov_diskfree_val.setText(tr("monitoring.na")) now = time.monotonic() try: diff --git a/ui/widgets.py b/ui/widgets.py index 35c80ac..8cfb0ce 100644 --- a/ui/widgets.py +++ b/ui/widgets.py @@ -50,8 +50,10 @@ class StatCard(QFrame): # sizeHint hundreds of px wide, forcing its WHOLE grid column open and # throwing every card in the row out of alignment. self.sub_lbl.setWordWrap(True) - lay.addWidget(self.title_lbl) + # Number first, name under it — the figure is what the eye is looking + # for, and it is how the audit page's tiles are drawn. lay.addWidget(self.value_lbl) + lay.addWidget(self.title_lbl) lay.addWidget(self.sub_lbl) def set(self, title: str, value: str, sub: str = "") -> None: @@ -100,8 +102,9 @@ class BudgetCard(QFrame): # sizeHint hundreds of px wide, forcing its WHOLE grid column open and # throwing every card in the row out of alignment. self.sub_lbl.setWordWrap(True) - lay.addWidget(self.title_lbl) + # Same order as StatCard: the number first, its name under it. lay.addWidget(self.value_lbl) + lay.addWidget(self.title_lbl) lay.addWidget(self.sub_lbl) row = QHBoxLayout()