From 300c10711e9197878e10252efa8d73c430d103bf Mon Sep 17 00:00:00 2001 From: Nam Pham Dinh Thanh Date: Tue, 18 Aug 2026 15:20:34 +0900 Subject: [PATCH] =?UTF-8?q?Fix=20the=20rail=20picker=20going=20nameless=20?= =?UTF-8?q?=E2=80=94=20my=20own=20regression=20from=20the=20row=20rework?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Giving each project row a widget left the QListWidgetItem with no text, and project_choices() read exactly that. So the rail's picker listed every project as a bare "📁 " with nothing after it, and the more projects there were the more identical blanks you got. Reported after creating a second one. Setting the text back on the item is not the fix: with a transparent row widget on top, the name paints twice, one string ghosting the other — visible in a render. project_choices() now reads list_projects(), the same source the list is built from, so the picker no longer depends on how a row happens to be drawn. check_project_screen creates a project and requires project_choices() to return non-empty names and the picker to show each of them. Pointing it back at item.text() fails it. 22/22 checkers pass. Co-Authored-By: Claude Opus 5 (1M context) --- tools/check_project_screen.py | 20 ++++++++++++++++++++ ui/workspace_tab.py | 16 ++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/tools/check_project_screen.py b/tools/check_project_screen.py index 67323a4..698d054 100644 --- a/tools/check_project_screen.py +++ b/tools/check_project_screen.py @@ -103,6 +103,26 @@ def main() -> int: fails.append(f"thieu nhan {label!r}") print(f"nhan form: {want}") + # 5. the rail's picker must name the projects. It reads project_choices(), + # which used to read item.text() — and when rows became widgets the item + # text went empty, so every entry showed as a bare folder glyph. Creating + # a project is when a user notices, so create one here. + before = [n for n, _pid in w.project_choices()] + w._create() + app.processEvents() + choices = w.project_choices() + picker = [win.nav_project.itemText(i) for i in range(win.nav_project.count())] + print(f"project_choices: {[n for n, _p in choices][:4]}") + print(f"picker hien thi: {picker[:4]}") + if any(not name.strip() for name, _pid in choices): + fails.append("project_choices tra ve ten rong") + if len(choices) <= len(before): + fails.append("tao project moi khong vao danh sach") + for name, _pid in choices: + if not any(name in text for text in picker): + fails.append(f"picker khong hien ten {name!r}") + break + print() for f in fails: print("FAIL " + f) diff --git a/ui/workspace_tab.py b/ui/workspace_tab.py index e8d5113..0b0f234 100644 --- a/ui/workspace_tab.py +++ b/ui/workspace_tab.py @@ -532,6 +532,8 @@ class WorkspaceTab(QWidget): row_to_select = 0 for i, p in enumerate(list_projects()): chats, tasks = counts.get(p.project_id, (0, 0)) + # No text on the item: the row widget paints the name, and setting + # both drew it twice, one string ghosting the other. item = QListWidgetItem() item.setData(Qt.UserRole, p.project_id) if p.description: @@ -622,10 +624,16 @@ class WorkspaceTab(QWidget): # ---- rail integration ------------------------------------------------- def project_choices(self): - """(name, project_id) for the rail picker, in the list's own order.""" - return [(self.project_list.item(i).text(), - self.project_list.item(i).data(Qt.UserRole)) - for i in range(self.project_list.count())] + """(name, project_id) for the rail picker, in the list's own order. + + Read from the store, which is what the list is built from — reading + item.text() coupled the picker to how a row happens to be drawn, and + when rows became widgets the picker went blank: every project showed + as a bare folder glyph with no name. + """ + from ..core.projects import list_projects + + return [(p.name, p.project_id) for p in list_projects()] def selected_project_id(self) -> str: return self._selected_id()