feat(ui): close the last gaps against the audit design (31/31)
check_design_parity.py reads its checklist from the audit page's own
proposals; it now reports every one of the 31 as implemented, with no
deliberate divergences left.
* Schedule: the Kanban/Calendar drop-list became a pair of tabs, and the
Running lane is outlined while it holds anything — dropping a card there
starts the task for real, so it should not look like the other six.
* Cowork: agent / routing / usage / folder moved out of the typing box into
their own status strip beneath it, styled as status rather than a second
toolbar. All of them stay interactive; the design's read-only strip would
have cost features.
* Folder: the path is written as the screen's title instead of sitting in a
read-only text box that looked editable and cost a row.
* GraphRAG: the second toolbar row is gone (Export joined the first), and
the one button that relabelled itself became Đồ thị | Tin nhắn tabs, so
the view you are NOT in is named too.
* Settings gained the theme picker, so language / provider / theme are all
reachable there as well as on the rail's account row.
* Task editor: the five group boxes are grouped into three step tabs
(Nội dung → Lịch chạy → Liên kết). All 22 fields verified present after
the move; only the old section index is gone, replaced by the tabs.
* The assistant dot now clears a screen's own bottom bar (Cowork's
composer), measured from the composer's top edge in window coordinates.
Also adds .gitattributes: without it a Windows checkout records CRLF and
every file reads as fully rewritten to a Linux CI runner.
Verification: 7 check_*.py suites green, no screen clipped at 1920/1366/1280,
and no dialog scrolls sideways at 9/11/14pt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+41
-29
@@ -18,7 +18,7 @@ from PySide6.QtGui import QBrush, QColor, QFont, QPen
|
||||
from PySide6.QtWidgets import (
|
||||
QComboBox, QFileDialog, QGraphicsEllipseItem, QGraphicsLineItem,
|
||||
QGraphicsScene, QGraphicsSimpleTextItem, QGraphicsView, QHBoxLayout,
|
||||
QLabel, QLineEdit, QPushButton, QSplitter, QStackedWidget,
|
||||
QLabel, QLineEdit, QPushButton, QSplitter, QStackedWidget, QTabBar,
|
||||
QTextBrowser, QVBoxLayout, QWidget,
|
||||
)
|
||||
|
||||
@@ -229,29 +229,36 @@ class StructureGraphView(QWidget):
|
||||
self._scan_btn.setIcon(icon("search"))
|
||||
self._scan_btn.setObjectName("primary")
|
||||
self._scan_btn.clicked.connect(self._scan)
|
||||
bar.addWidget(self.path_edit, 1)
|
||||
bar.addWidget(self._pick_btn)
|
||||
bar.addWidget(self.project_combo)
|
||||
bar.addWidget(self._scan_btn)
|
||||
root.addLayout(bar)
|
||||
self._refresh_project_combo()
|
||||
|
||||
# Toolbar: messages toggle + export
|
||||
bar2 = QHBoxLayout()
|
||||
bar2.addStretch(1)
|
||||
self._msgs_toggle_btn = QPushButton()
|
||||
self._msgs_toggle_btn.setIcon(icon("message"))
|
||||
self._msgs_toggle_btn.setToolTip(tr("structure.msgs_tooltip"))
|
||||
self._msgs_toggle_btn.clicked.connect(self._toggle_messages)
|
||||
bar2.addWidget(self._msgs_toggle_btn)
|
||||
|
||||
# ONE toolbar row. There used to be a second row holding just the
|
||||
# messages toggle and Export, which cost a whole row of height to carry
|
||||
# two buttons.
|
||||
self._export_btn = QPushButton()
|
||||
self._export_btn.setIcon(icon("upload"))
|
||||
self._export_btn.setObjectName("primary")
|
||||
self._export_btn.clicked.connect(self._export)
|
||||
bar2.addWidget(self._export_btn)
|
||||
bar.addWidget(self.path_edit, 1)
|
||||
bar.addWidget(self._pick_btn)
|
||||
bar.addWidget(self.project_combo)
|
||||
bar.addWidget(self._scan_btn)
|
||||
bar.addWidget(self._export_btn)
|
||||
root.addLayout(bar)
|
||||
self._refresh_project_combo()
|
||||
|
||||
root.addLayout(bar2)
|
||||
# Đồ thị | Tin nhắn as a real pair of tabs: the old single button
|
||||
# relabelled itself, so the view you were NOT looking at was the only
|
||||
# one named on screen.
|
||||
self.view_tabs = QTabBar()
|
||||
self.view_tabs.setObjectName("viewTabs")
|
||||
self.view_tabs.setDrawBase(False)
|
||||
self.view_tabs.setExpanding(False)
|
||||
self.view_tabs.addTab(icon("graph"), "")
|
||||
self.view_tabs.addTab(icon("message"), "")
|
||||
self.view_tabs.currentChanged.connect(self._on_view_tab)
|
||||
tab_row = QHBoxLayout()
|
||||
tab_row.setContentsMargins(0, 0, 0, 0)
|
||||
tab_row.addWidget(self.view_tabs)
|
||||
tab_row.addStretch(1)
|
||||
root.addLayout(tab_row)
|
||||
|
||||
split = QSplitter(Qt.Horizontal)
|
||||
self.scene = QGraphicsScene()
|
||||
@@ -337,8 +344,10 @@ class StructureGraphView(QWidget):
|
||||
self._pick_btn.setText(tr("structure.browse"))
|
||||
self._scan_btn.setText(tr("structure.scan"))
|
||||
self._export_btn.setText(tr("structure.export_png"))
|
||||
showing = self._stack.currentWidget() is getattr(self, "_msgs_view", None)
|
||||
self._msgs_toggle_btn.setText(tr("structure.graph_btn") if showing else tr("structure.msgs_btn"))
|
||||
# Both views are named at once now, so neither label depends on state.
|
||||
self.view_tabs.setTabText(0, tr("structure.graph_btn"))
|
||||
self.view_tabs.setTabText(1, tr("structure.msgs_btn"))
|
||||
self.view_tabs.setTabToolTip(1, tr("structure.msgs_tooltip"))
|
||||
self._ag_collapse.setToolTip(tr("structure.collapse_agent_tooltip"))
|
||||
self._ag_label.setText(tr("structure.agent_header"))
|
||||
self.ask_edit.setPlaceholderText(tr("structure.ask_placeholder"))
|
||||
@@ -413,16 +422,19 @@ class StructureGraphView(QWidget):
|
||||
self._rescan_timer.start()
|
||||
|
||||
# ---- Messages (by day, as JSON) --------------------------------------
|
||||
def _toggle_messages(self) -> None:
|
||||
"""Switch between the knowledge graph and the Messages-by-day view."""
|
||||
showing = self._stack.currentWidget() is self._msgs_view
|
||||
if showing:
|
||||
self._stack.setCurrentWidget(self.web if self.web is not None else self.view)
|
||||
else:
|
||||
def _on_view_tab(self, index: int) -> None:
|
||||
"""Tab 0 = graph, tab 1 = messages. Same two views as before, now named
|
||||
on screen instead of hidden behind one button's changing label."""
|
||||
if index == 1:
|
||||
self._reload_messages()
|
||||
self._stack.setCurrentWidget(self._msgs_view)
|
||||
self._msgs_toggle_btn.setText(
|
||||
tr("structure.graph_btn") if not showing else tr("structure.msgs_btn"))
|
||||
else:
|
||||
self._stack.setCurrentWidget(self.web if self.web is not None else self.view)
|
||||
|
||||
def _toggle_messages(self) -> None:
|
||||
"""Kept for callers that still ask for a flip (e.g. keyboard paths)."""
|
||||
showing = self._stack.currentWidget() is self._msgs_view
|
||||
self.view_tabs.setCurrentIndex(0 if showing else 1)
|
||||
|
||||
def _reload_messages(self) -> None:
|
||||
"""Build the tree: day → conversation. Click a conversation to see its
|
||||
|
||||
Reference in New Issue
Block a user