Close the remaining gaps on Project and Cowork against the wireframes

Re-read both drawings element by element rather than by eye. Five things were
still wrong.

Cowork headed itself "Cowork" — the screen's own name, which the rail already
shows — where the drawing puts the THREAD's title. The title now follows the
conversation, falling back to the screen name for a chat that has none yet;
ChatPanel notifies on load, on reset and when a title is first derived from the
opening turn.

Its files panel read "Tệp đầu ra"; every section heading in the drawings is
caps, so it matches the rail and Monitoring now.

Project kept its three-line explanation above the panes on every visit. The
drawing heads a populated screen with the title alone and gives the text to the
EMPTY state instead, which is where it is actually needed — so it shows only
when there is no project yet.

The workspace path sat as grey caption text where the drawing shows a field. A
read-only line edit looks like one and lets the path be selected and copied.

And Lưu project sat directly under the folder row; the drawing floats it at the
foot of the panel, so a stretch went in above it.

Checked against the control inventory, not just the picture: "Nén" and "Thư mục
Local…" are marked giữ nguyên tại chỗ, so they stay in the status strip even
though the drawing's status line is text only.

New check_cowork_screen; check_project_screen gains the three points. Both
mutation-tested — pinning the title back to tr("cowork.title") and making the
hint unconditional each fail.

23/23 checkers pass. The Qt teardown segfault is still around: check_no_hscroll
took it 1 run in 3, after printing its verdict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nam Pham Dinh Thanh
2026-08-18 15:38:46 +09:00
co-authored by Claude Opus 5
parent 300c10711e
commit 7d9a4e2378
5 changed files with 157 additions and 7 deletions
+11 -2
View File
@@ -84,6 +84,7 @@ class ChatPanel(QWidget):
self.session_name = session_name
self.session_id = new_session_id()
self.title = ""
self._notify_title()
# Which project (workspace) this conversation belongs to — every new
# thread inherits the currently selected project (Claude-Projects style).
self.project_id = "default"
@@ -202,7 +203,7 @@ class ChatPanel(QWidget):
# Right sidebar: Output files only (see below — Input is tracked but
# not shown).
self.input_section = CollapsibleSection(tr("widgets.input_files"))
self.output_section = CollapsibleSection(tr("widgets.output_files"))
self.output_section = CollapsibleSection(tr("widgets.output_files").upper())
# Input files are NOT shown in Cowork's UI anymore — but they're still
# fully tracked (add/remove/paths()) exactly as before, since that list
# is what gets written into the conversation's own "inputs" field on
@@ -285,7 +286,7 @@ class ChatPanel(QWidget):
self.compress_btn.setText(tr("chatpanel.compress_btn"))
self.compress_btn.setToolTip(tr("chatpanel.compress_tooltip"))
self.input_section.set_title(tr("widgets.input_files"))
self.output_section.set_title(tr("widgets.output_files"))
self.output_section.set_title(tr("widgets.output_files").upper())
self.plan_section.set_title(tr("widgets.plan_title"))
self._io_collapse_btn.setToolTip(tr("chatpanel.collapse_files_tooltip"))
self._files_header.setText(tr("chatpanel.files_header"))
@@ -1024,6 +1025,7 @@ class ChatPanel(QWidget):
if not self.title:
base = text or (Path(attachments[0]).name if attachments else "(attachment)")
self.title = (base[:60] + "…") if len(base) > 60 else base
self._notify_title()
# Reset the Plan panel so each message starts from a clean checklist (the
# previous message's plan never lingers/flickers into this one).
@@ -1669,6 +1671,12 @@ class ChatPanel(QWidget):
self._sync_indicators()
self.history_changed.emit() # current view changed → refresh History highlight
def _notify_title(self) -> None:
"""Let a screen that heads itself with the thread title follow along."""
hook = getattr(self, "refresh_title", None)
if callable(hook):
hook()
def load_conversation(self, conv: Dict[str, Any]) -> None:
"""Switch the view to a stored conversation. Allowed while work is running —
the current turns keep going in the background."""
@@ -1680,6 +1688,7 @@ class ChatPanel(QWidget):
self._detach_live_turns()
self.session_id = sid
self.title = conv.get("title", "")
self._notify_title()
self.project_id = conv.get("project_id", "") or "default"
# If this conversation still has a turn running in the background, attach to
# its LIVE message list (not a stale disk copy) so the two never race on save.