I read "chevron gập pane Lịch sử — giữ" as "keep it as a strip" and left an 18px sliver down the side. The drawing has nothing there: the body row is two columns, transcript and files, and the relocation table settles it — History (lịch sử chat), was "pane giữa, chỉ ở tab Cowork", now "Sidebar ▸ RECENTS", verdict "giữ, dễ tới hơn". The line about the chevron belongs to a tally of the app's eleven collapsible spots, not to this screen's layout. So the panel is not on Cowork at all. "Tất cả project…" in RECENTS brings it in at full width — it has to stay reachable, because search, filters, pin, rename and multi-select delete exist nowhere else — and its chevron puts it away again. Either choice survives leaving the screen and coming back. check_cowork_screen now requires it absent on arrival and present after the request; showing it unconditionally fails. 23/23 checkers pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
156 lines
5.9 KiB
Python
156 lines
5.9 KiB
Python
"""Workspace ▸ Cowork against its wireframe (section 5).
|
||
|
||
The drawing heads the screen with the THREAD's title — "Gom số liệu doanh thu",
|
||
not the word "Cowork" — with the model beside it, Skills and Cuộc trò chuyện mới
|
||
on the right, and a caps TỆP ĐẦU RA (n) panel down the side.
|
||
"""
|
||
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.QtWidgets import QApplication
|
||
|
||
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.core.history import list_conversations, load_conversation
|
||
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(1920, 1000)
|
||
win.show()
|
||
app.processEvents()
|
||
win._goto(win._ROW_WORKSPACE, win.workspace._cowork_tab_idx)
|
||
app.processEvents()
|
||
c = win.cowork
|
||
fails = []
|
||
|
||
# a new thread has no title yet, so the screen name stands in
|
||
print(f"chua mo thread: tieu de={c._title_lbl.text()!r}")
|
||
if not c._title_lbl.text().strip():
|
||
fails.append("tieu de trong khi chua mo thread")
|
||
|
||
convs = list_conversations()
|
||
if not convs:
|
||
fails.append("khong co hoi thoai de kiem")
|
||
else:
|
||
conv = load_conversation(Path(convs[0]["path"]))
|
||
c.load_conversation(conv)
|
||
app.processEvents()
|
||
want = conv.get("title", "")
|
||
print(f"sau khi mo thread: tieu de={c._title_lbl.text()!r} (thread={want!r})")
|
||
if want and c._title_lbl.text() != want:
|
||
fails.append(f"tieu de khong theo thread: {c._title_lbl.text()!r} != {want!r}")
|
||
if c._title_lbl.text() == tr("cowork.title") and want:
|
||
fails.append("tieu de van la ten man hinh")
|
||
|
||
# the files panel is a caps section carrying its own count
|
||
head = c.output_section.header.text()
|
||
print(f"pane tep dau ra: {head!r}")
|
||
body = head.lstrip("▾▸ ").split(" (")[0]
|
||
if body != body.upper():
|
||
fails.append(f"tieu de pane chua viet hoa: {head!r}")
|
||
if "(" not in head:
|
||
fails.append("tieu de pane khong kem so luong")
|
||
|
||
# toolbar keeps both actions the drawing shows
|
||
for name, btn in (("Skills", c.skills_btn), ("chat moi", c._new_btn)):
|
||
if not btn.isVisible():
|
||
fails.append(f"thieu nut {name} tren thanh cong cu")
|
||
print(f"nut tren thanh cong cu: {c.skills_btn.text()!r}, {c._new_btn.text()!r}")
|
||
|
||
# the drawing gives Cowork two columns; History lives in the rail's RECENTS
|
||
# and its pane arrives folded to the strip the drawing keeps
|
||
w = win.workspace
|
||
sb = w._sidebar
|
||
print(f"vao Cowork: History hien={sb.isVisible()}")
|
||
if sb.isVisible():
|
||
fails.append("pane Lich su van o tren man Cowork — ban ve chi co 2 cot")
|
||
w.show_history_pane()
|
||
app.processEvents()
|
||
print(f"sau 'Tat ca project…': History hien={sb.isVisible()} rong={sb.width()}px")
|
||
if not sb.isVisible():
|
||
fails.append("'Tat ca project…' khong mo duoc pane Lich su")
|
||
w._on_history_fold(True)
|
||
app.processEvents()
|
||
|
||
# one heading on the files panel, with the chevron at its right — the
|
||
# drawing has "TỆP ĐẦU RA (3) ›" and nothing above it
|
||
from PySide6.QtCore import QPoint as _QP
|
||
|
||
hdr_w = c.output_section.header
|
||
chev = c._io_collapse_btn
|
||
same_row = abs(hdr_w.mapTo(c, _QP(0, 0)).y() - chev.mapTo(c, _QP(0, 0)).y()) <= 8
|
||
chev_right = chev.mapTo(c, _QP(0, 0)).x() > hdr_w.mapTo(c, _QP(0, 0)).x()
|
||
# Count what the panel actually shows as headings. Asking whether the old
|
||
# label is visible proved nothing: unparented, it reports invisible whether
|
||
# or not the code hides it.
|
||
from PySide6.QtWidgets import QLabel
|
||
|
||
heads = [l.text() for l in c._io_widget.findChildren(QLabel)
|
||
if l.isVisible() and l.text().strip()]
|
||
print(f"tieu de hien trong pane: {heads} | "
|
||
f"chevron cung hang={same_row} ben phai={chev_right}")
|
||
if heads:
|
||
fails.append(f"pane co tieu de thua ngoai '{hdr_w.text()}': {heads}")
|
||
if not (same_row and chev_right):
|
||
fails.append("chevron thu gon khong nam cuoi hang tieu de pane")
|
||
|
||
# the composer spans the screen, under BOTH columns — inside the chat
|
||
# column it stopped at the files panel's edge and shrank when files arrived
|
||
from PySide6.QtCore import QPoint
|
||
|
||
c._set_io_collapsed(False)
|
||
app.processEvents()
|
||
split = c.center_split
|
||
files_pane = split.widget(1)
|
||
comp_right = c.composer.mapTo(c, QPoint(c.composer.width(), 0)).x()
|
||
files_left = files_pane.mapTo(c, QPoint(0, 0)).x()
|
||
below = c.composer.mapTo(c, QPoint(0, 0)).y() > split.mapTo(c, QPoint(0, 0)).y()
|
||
spans = comp_right > files_left
|
||
print(f"o nhap: rong {c.composer.width()} / man {c.width()} | "
|
||
f"duoi splitter={below} | trai qua duoi pane tep={spans}")
|
||
if not below:
|
||
fails.append("o nhap khong nam duoi hang than")
|
||
if not spans:
|
||
fails.append("o nhap dung lai o mep pane tep, khong trai het man")
|
||
|
||
print()
|
||
for f in fails:
|
||
print("FAIL " + f)
|
||
print("PASS man Cowork 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())
|