Files
cowork-local/tools/check_dashboard.py
T
anhtnm1andClaude Opus 5 81b9482011 fix(tools): 5 checker UI hỏng sau đợt tách widget R08
`tools/` không đổi một byte nào giữa hai bản, nhưng 5 checker vẫn chết vì
chúng tìm control bằng `getattr(root, "ten")` trên đúng widget cũ — mà R08 đã
dời control xuống widget con.

Thêm ba helper dùng chung vào `capture_screens.py`:
  * `_own_member` — tên do app khai trên widget, không phải thừa kế từ Qt
  * `owner_of`   — widget thật sự đang giữ tên đó, duyệt theo bề rộng
  * `control`    — lấy control dù nó nằm ở cấp nào

`check_controls_alive` từ "MẤT 24 control" về 0, kèm liệt kê 22 control đã
đổi chỗ và 2 cái đổi tên. `check_probes_bite` từ 1/4 lên 6/6 phép cấy lỗi đều
bị bắt — phép cấy thứ hai trỏ vào `ui/schedule_task_tab.py` đã bị xoá, nay
trỏ vào `presentation/scheduling/kanban_board_widget.py`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 10:37:06 +09:00

101 lines
3.4 KiB
Python

"""Check the Dashboard header regroup, on the real widget, offscreen.
Nine controls were on one row. They are now on two, grouped by what they do —
so this asserts that all nine are still present, still wired, and that the
header really is two rows now (row 1 = title + Refresh, row 2 = the selectors).
Run: python tools/check_dashboard.py
"""
from __future__ import annotations
import os
import sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO.parent))
sys.path.insert(0, str(Path(__file__).resolve().parent))
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from capture_screens import _apply_theme, _isolate_home, _load_fonts, control # noqa: E402
HEADER = ["_title", "chart_prev_btn", "_chart_period_lbl", "chart_next_btn",
"gran_combo", "metric_combo", "currency_lbl", "currency_combo",
"refresh_btn"]
def main() -> int:
sandbox = _isolate_home()
from PySide6.QtWidgets import QApplication
app = QApplication([])
_load_fonts()
_apply_theme(app) # measure the styled widget, not a bare one
from cowork_local.config import AppConfig, CONFIG_DIR
assert str(sandbox) in str(CONFIG_DIR), f"isolation failed: {CONFIG_DIR}"
from seed_demo_data import seed
seed()
from cowork_local.i18n import set_language
from cowork_local.state import AppContext
# R08-T13 moved the screen out of ui/ into presentation/dashboard/ and
# split its header controls across UsageChartWidget / HabitsWidget, so
# every control below is looked up through `control()` rather than as a
# direct attribute of the tab.
from cowork_local.presentation.dashboard.dashboard_tab import DashboardTab
set_language("vi")
tab = DashboardTab(AppContext(AppConfig.load()))
tab.resize(1100, 800)
tab.show()
app.processEvents()
tab.refresh()
app.processEvents()
fails: list[str] = []
missing = [n for n in HEADER if control(tab, n) is None]
print(f"control header con nguyen: {len(HEADER) - len(missing)}/{len(HEADER)}")
if missing:
fails.append(f"mat control: {missing}")
# Two rows: everything in the header must sit at one of exactly two y bands.
tops = {}
for n in HEADER:
w = control(tab, n)
tops.setdefault(round(w.mapTo(tab, w.rect().topLeft()).y() / 10), []).append(n)
print(f"so hang cua header : {len(tops)}")
for band, names in sorted(tops.items()):
print(f" y~{band * 10:>4}px : {names}")
if len(tops) != 2:
fails.append(f"header co {len(tops)} hang, cho 2")
# Still wired: changing the metric must not throw and must stick.
metric = control(tab, "metric_combo")
before = metric.currentData()
metric.setCurrentIndex(1 - metric.currentIndex())
app.processEvents()
after = metric.currentData()
print(f"doi chi so bieu do : {before} -> {after}")
if after == before:
fails.append("combo chi so khong doi duoc")
control(tab, "refresh_btn").click()
app.processEvents()
print("bam Lam moi : khong loi")
print()
if fails:
print("*** LOI ***")
for f in fails:
print(" " + f)
return 1
print("KET QUA: header Dashboard chia 2 hang, du 9 control")
return 0
if __name__ == "__main__":
raise SystemExit(main())