fix(ui): sections 17 and 18 were checked against the wrong text
check_design_parity read its checklist from build_audit_page.ANALYSIS. Eight
sections of the audit page are hand-written, and for those the generator's
text is NOT what the page says — so Settings and the Task editor were reported
as matching a design they had never been compared against. The Task editor was
in fact built backwards.
* The checker now reads the "Thay đổi" bullets straight out of
docs/ui-audit.html, and reports how many bullets on the page still have no
probe (57 on the page, 32 probed) instead of implying full coverage.
* Task editor: reverted from three step tabs to a left list + right panel,
five rows matching the five real group boxes — which is what the page asks
for, in as many words ("thay vì chia tab"), for consistency with Settings.
* Settings now switches panels rather than scrolling, so both dialogs are
navigated identically and neither is a long scroll any more.
* Settings field presentation, as the page's second bullet asks: the six
checkboxes became switches, and Language/Theme became segmented controls.
ToggleSwitch subclasses QCheckBox and SegmentedControl exposes the slice
of the QComboBox API this dialog uses, so no save/load path changed —
verified by round-tripping language/theme/tray through _save().
All 22 task-editor fields and 14 settings fields verified present after the
move; 7 suites green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,29 @@ os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
from capture_screens import _freeze_schedulers, _isolate_home, _load_fonts # noqa: E402
|
||||
|
||||
|
||||
def page_proposals():
|
||||
"""The 'Thay đổi' bullets as they appear ON THE PAGE, per section.
|
||||
|
||||
Read from docs/ui-audit.html rather than build_audit_page.ANALYSIS: eight
|
||||
sections are hand-written, and for those two the generator's text is NOT
|
||||
what the page shows. Checking against ANALYSIS reported Settings and the
|
||||
Task editor as matching the design when the page asked for something else
|
||||
(and, for the Task editor, the opposite).
|
||||
"""
|
||||
import re
|
||||
html = (REPO / "docs" / "ui-audit.html").read_text(encoding="utf-8")
|
||||
html = re.sub(r"data:image/png;base64,[A-Za-z0-9+/=]+", "", html)
|
||||
out: dict[str, list[str]] = {}
|
||||
for m in re.finditer(r'<section class="sec" id="([^"]+)">(.*?)</section>', html, re.S):
|
||||
block = re.search(r'Thay đổi</div><ul class="pr">(.*?)</ul>', m.group(2), re.S)
|
||||
if not block:
|
||||
continue
|
||||
out[m.group(1)] = [
|
||||
re.sub(r"\s+", " ", re.sub(r"<[^>]+>", "", li)).strip()
|
||||
for li in re.findall(r"<li>(.*?)</li>", block.group(1), re.S)]
|
||||
return out
|
||||
|
||||
|
||||
def build():
|
||||
sandbox = _isolate_home()
|
||||
from PySide6.QtWidgets import QApplication
|
||||
@@ -213,6 +236,7 @@ def main() -> int:
|
||||
|
||||
# --- 9/15 Monitoring ---
|
||||
from PySide6.QtWidgets import QHBoxLayout, QScrollArea
|
||||
from PySide6.QtWidgets import QSpinBox as QSpinBoxT
|
||||
ov = mon.findChildren(QScrollArea)[0].widget()
|
||||
one_col = not isinstance(ov.layout(), QHBoxLayout)
|
||||
add("monitoring-tổng-quan", "Một cột chính, mục có tiêu đề", one_col,
|
||||
@@ -232,15 +256,31 @@ def main() -> int:
|
||||
s = SettingsDialog(win.ctx)
|
||||
add("dialog-settings", "Thêm cột mục lục bên trái",
|
||||
s.section_list.count() == 5, f"{s.section_list.count()} mục")
|
||||
have = [n for n in ("provider_combo", "language_combo", "theme_combo")
|
||||
if getattr(s, n, None) is not None]
|
||||
add("dialog-settings", "Gom Provider/Ngôn ngữ/Giao diện vào Settings",
|
||||
len(have) == 3, f"{have} (cũng có ở hàng tài khoản trên rail)")
|
||||
# The page asks for Ngôn ngữ/Giao diện in the Chung group, with AI Provider
|
||||
# left as its own group — not everything merged together.
|
||||
from cowork_local.ui.widgets import SegmentedControl, ToggleSwitch
|
||||
in_general = s._general_box.isAncestorOf(s.language_combo) and \
|
||||
s._general_box.isAncestorOf(s.theme_combo)
|
||||
prov_apart = not s._general_box.isAncestorOf(s.provider_combo)
|
||||
add("dialog-settings", "Gom Ngôn ngữ/Giao diện vào nhóm Chung; AI Provider vẫn riêng",
|
||||
in_general and prov_apart,
|
||||
f"ngôn ngữ+giao diện trong Chung={in_general} · provider tách riêng={prov_apart}")
|
||||
n_switch = len(s.findChildren(ToggleSwitch))
|
||||
n_seg = len(s.findChildren(SegmentedControl))
|
||||
steppers = [w for w in s.findChildren(QSpinBoxT) if w.buttonSymbols() != 2]
|
||||
add("dialog-settings",
|
||||
"Field theo đúng loại: checkbox→toggle, dropdown 2–4 giá trị→segmented, số→stepper",
|
||||
n_switch >= 6 and n_seg >= 2 and len(steppers) >= 1,
|
||||
f"{n_switch} toggle · {n_seg} segmented · {len(steppers)} stepper")
|
||||
s.close()
|
||||
t = TaskEditorDialog(ctx=win.ctx)
|
||||
steps = [t.step_tabs.tabText(i) for i in range(t.step_tabs.count())]
|
||||
add("dialog-task-editor", "Chia 3 bước có tab: Nội dung → Lịch chạy → Liên kết",
|
||||
len(steps) == 3, " · ".join(steps))
|
||||
rows = [t.section_list.item(i).text() for i in range(t.section_list.count())]
|
||||
like_settings = (t.section_list.count() == 5
|
||||
and t.section_stack.count() == 5
|
||||
and not hasattr(t, "step_tabs"))
|
||||
add("dialog-task-editor",
|
||||
"Danh sách trái + panel phải giống Cài đặt (không dùng tab), 5 mục = 5 group",
|
||||
like_settings, " · ".join(rows))
|
||||
t.close()
|
||||
|
||||
# --- 27 help dock ---
|
||||
@@ -269,6 +309,19 @@ def main() -> int:
|
||||
dock_top + dock.height() <= comp_top,
|
||||
f"chấm đáy y={dock_top + dock.height()} · ô nhập đỉnh y={comp_top}")
|
||||
|
||||
# --- coverage: is every bullet ON THE PAGE actually probed? -------------
|
||||
proposals = page_proposals()
|
||||
probed = {}
|
||||
for slug, text, _v, _e in R:
|
||||
probed.setdefault(slug, 0)
|
||||
probed[slug] += 1
|
||||
gaps = []
|
||||
for slug, bullets in proposals.items():
|
||||
n_probe = probed.get(slug, 0)
|
||||
if len(bullets) > n_probe:
|
||||
for extra in bullets[n_probe:]:
|
||||
gaps.append((slug, extra))
|
||||
|
||||
# --- report ---
|
||||
order = ["OK", "KHAC", "CHUA", "TAY"]
|
||||
counts = {k: 0 for k in order}
|
||||
@@ -280,7 +333,15 @@ def main() -> int:
|
||||
cur = slug
|
||||
print(f" [{verdict:4}] {text}")
|
||||
print(f" {ev}")
|
||||
if gaps:
|
||||
print()
|
||||
print(f"*** DE XUAT TREN TRANG CHUA CO PHEP DO: {len(gaps)} ***")
|
||||
for slug, text in gaps:
|
||||
print(f" {slug}")
|
||||
print(f" {text[:160]}")
|
||||
print()
|
||||
print(f"de xuat tren trang : {sum(len(v) for v in proposals.values())}"
|
||||
f" · da co phep do : {len(R)}")
|
||||
print("TONG KET: " + " · ".join(f"{k}={counts.get(k, 0)}" for k in order))
|
||||
print(f" OK = dung thiet ke moi ({counts['OK']}/{len(R)})")
|
||||
print(f" KHAC = co y lam khac, da ghi ly do")
|
||||
|
||||
Reference in New Issue
Block a user