Rework Workspace ▸ Project to its wireframe
Section 4 draws a "Quản lý project" title with + Project mới on its right, a caps PROJECT heading over the list, every row carrying "N đoạn chat · M task", and the form reading Tên / Mô tả / Instructions / Thư mục làm việc. The screen had none of that: the header still said "Workspace — Projects", the create button sat at the foot of the list among the list's own controls, rows were bare names, the folder field had no label, and Instructions carried a parenthetical the drawing does not. The row counts are the substantive part — they are the only thing on the screen that says a project contains anything. Read once per refresh from list_conversations() and list_tasks() grouped by project_id, not per row. Delete stays under the list it acts on. The drawing does not show it, but it does not show it moved either, and dropping a control is not something a layout pass gets to do. Also shortened by the drawing: "Đổi thư mục…"/"Mở thư mục" to "Đổi"/"Mở", which the new "Thư mục làm việc" label above them now disambiguates. check_project_screen covers the four points and fails when the count line is removed. 22/22 checkers pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
416d88d72f
commit
9393fc1748
@@ -0,0 +1,115 @@
|
||||
"""Workspace ▸ Project against its wireframe (section 4).
|
||||
|
||||
The drawing: a "Quản lý project" title with + Project mới on its right, a caps
|
||||
PROJECT heading over the list, every row carrying "N đoạn chat · M task", and
|
||||
the form reading Tên / Mô tả / Instructions / Thư mục làm việc.
|
||||
"""
|
||||
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 ( # noqa: E402
|
||||
_apply_theme, _freeze_schedulers, _isolate_home, _load_fonts)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
sandbox = _isolate_home()
|
||||
from PySide6.QtCore import QPoint
|
||||
from PySide6.QtWidgets import QApplication, QLabel
|
||||
|
||||
app = QApplication([])
|
||||
_load_fonts()
|
||||
_freeze_schedulers()
|
||||
_apply_theme(app)
|
||||
|
||||
from cowork_local.config import CONFIG_DIR
|
||||
assert str(sandbox) in str(CONFIG_DIR), f"isolation failed: {CONFIG_DIR}"
|
||||
|
||||
from seed_demo_data import seed
|
||||
seed()
|
||||
|
||||
from cowork_local.app import MainWindow
|
||||
from cowork_local.config import AppConfig
|
||||
from cowork_local.i18n import set_language, tr
|
||||
from cowork_local.state import AppContext
|
||||
|
||||
set_language("vi")
|
||||
win = MainWindow(AppContext(AppConfig.load()), user_name="local")
|
||||
win.resize(1400, 900)
|
||||
win.show()
|
||||
app.processEvents()
|
||||
win._goto(win._ROW_WORKSPACE, win.workspace._project_tab_idx)
|
||||
app.processEvents()
|
||||
|
||||
w = win.workspace
|
||||
fails = []
|
||||
|
||||
# 1. title, and the create button on its row, to its right
|
||||
print(f"tieu de: {w._header.text()!r}")
|
||||
if w._header.text() != tr("workspace.header"):
|
||||
fails.append("tieu de khong phai workspace.header")
|
||||
h_pos = w._header.mapTo(w, QPoint(0, 0))
|
||||
h_mid = h_pos.y() + w._header.height() // 2
|
||||
b_pos = w._new_btn.mapTo(w, QPoint(0, 0))
|
||||
b_mid = b_pos.y() + w._new_btn.height() // 2
|
||||
aligned = abs(b_mid - h_mid) <= 8
|
||||
after = b_pos.x() >= h_pos.x() + w._header.width()
|
||||
print(f"nut '+ Project mới': tam y={b_mid} (tieu de {h_mid}) thang hang={aligned} "
|
||||
f"| x={b_pos.x()} sau tieu de={after}")
|
||||
if not (aligned and after):
|
||||
fails.append("nut tao project khong nam cung hang, ben phai tieu de")
|
||||
|
||||
# 2. caps heading over the list
|
||||
hdr = w._projects_hdr.text()
|
||||
print(f"tieu de pane trai: {hdr!r}")
|
||||
if not hdr or hdr != hdr.upper():
|
||||
fails.append(f"tieu de pane trai chua viet hoa: {hdr!r}")
|
||||
|
||||
# 3. every row says how much is in the project
|
||||
lst = w.project_list
|
||||
if not lst.count():
|
||||
fails.append("khong co project nao de kiem")
|
||||
shown = 0
|
||||
for i in range(lst.count()):
|
||||
row = lst.itemWidget(lst.item(i))
|
||||
labels = [l.text() for l in row.findChildren(QLabel)] if row else []
|
||||
if len(labels) < 2:
|
||||
fails.append(f"hang {i} khong co dong dem chat/task")
|
||||
continue
|
||||
shown += 1
|
||||
if i < 2:
|
||||
print(f" hang {i}: {labels[0]!r} / {labels[1]!r}")
|
||||
# the sub-line must be the counts string, not the name repeated
|
||||
if labels[1] == labels[0] or not any(ch.isdigit() for ch in labels[1]):
|
||||
fails.append(f"hang {i}: dong phu khong phai so dem: {labels[1]!r}")
|
||||
print(f"so hang co dong dem: {shown}/{lst.count()}")
|
||||
|
||||
# 4. the form reads as the drawing labels it
|
||||
want = [tr("workspace.name"), tr("workspace.description"),
|
||||
tr("workspace.instructions"), tr("workspace.folder_label")]
|
||||
seen = [l.text() for l in w.findChildren(QLabel) if l.isVisible() and l.text()]
|
||||
for label in want:
|
||||
if label not in seen:
|
||||
fails.append(f"thieu nhan {label!r}")
|
||||
print(f"nhan form: {want}")
|
||||
|
||||
print()
|
||||
for f in fails:
|
||||
print("FAIL " + f)
|
||||
print("PASS man Project khop ban ve" if not fails else f"{len(fails)} problem(s)")
|
||||
sys.stdout.flush()
|
||||
os._exit(1 if fails else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user