You are right that the new Cowork should not carry a History pane. The page
lists it under "Thành phần bị dời chỗ": History, pane giữa, chỉ ở tab Cowork →
Sidebar ▸ RECENTS. Its own complaint about this screen is that three panes
squeezed the conversation under 60% of the width, and the wireframe draws two
columns — transcript and files.
But the same page also keeps the pane's chevron ("Pane Lịch sử: chevron trên
đầu History, gập thành dải mỏng — giữ"), and RECENTS ends in "Tất cả project…",
which opens it. So it is folded, not gone: search, filters, pin, rename and
multi-select delete only exist in that panel and deleting it would take them.
Cowork now opens with History folded to its 18px strip. "Tất cả project…" opens
it to 240px, and either choice is remembered — leaving the screen and coming
back no longer re-folds a panel you just opened, or re-opens one you just shut.
check_cowork_screen requires the fold on arrival and the strip to open on
request; restoring the old auto-expand fails it.
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 gap={sb.is_collapsed()} rong={sb.width()}px")
|
||
if not sb.is_collapsed():
|
||
fails.append("pane Lich su mo san — man Cowork thanh 3 cot")
|
||
w.show_history_pane()
|
||
app.processEvents()
|
||
print(f"sau 'Tat ca project…': History gap={sb.is_collapsed()} rong={sb.width()}px")
|
||
if sb.is_collapsed():
|
||
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())
|