refactor: vá 4 hồi quy, tách 4 file chạm trần LOC, docstring lên 100%
Hồi quy đã vá
-------------
F-12 Kéo–thả hoặc dán tệp vào ô chat ném NameError. R08 tách `_Input` sang
`chat_input_box.py` nhưng để `_paths_from_mime()` ở lại
`composer_widget.py`, nên hai hàm sự kiện Qt gọi một cái tên không tồn
tại. Bốn hàm dùng chung chuyển sang `composer_mime.py` — module thứ ba
là chỗ duy nhất không lặp lại được lỗi này. Đo lại: cả thả lẫn dán đều
gắn 1 tệp, khớp bản trước refactor.
F-01 Đổi provider thì bộ chọn model AI-Edit không làm gì. Hook cũ kiểm
`folder.ai_model_combo`, thuộc tính R08-T12 đã dời sang
`ai_panel.resolver`. Làm mới vô điều kiện, đúng như tab cũ: lần lấy đầu
tiên hỏng thì đổi provider chính là lúc phải thử lại.
F-07 Hàng chọn kỳ của Dashboard bị đẩy xuống dưới các thẻ số liệu. Hàng này
lọc CẢ BA thẻ con chứ không riêng biểu đồ, nên để nó nằm dưới là bắt
người dùng đọc con số trước khi thấy con số đó tính cho kỳ nào. Kèm
theo: `TokenUsageCardWidget` bị bỏ sót `setContentsMargins(0,0,0,0)`
mà hai thẻ con còn lại đã có, đẩy cả hàng thẻ lệch 9px.
`check_layout_geometry` nay khớp TỪNG BYTE với bản trước refactor.
F-11 Hai lớp khai trùng tên phương thức; Python giữ bản sau nên bản đầu là
mã chết. `co4e_tab.py::showEvent` bản đầu gọi `_narrow_guard.attach()`
và không bao giờ chạy.
Tách file (F-09)
----------------
Bốn file chạm trần 400 dòng, mỗi lần cắt ra một trách nhiệm thật:
graph_renderer.py -> graph_scene_builder.py + graph_export.py
co4e_workflow_service.py -> co4e_run_history.py
json_config_repository.py -> config_sections.py
agents_admin_tab.py -> shared/agent_kind_visuals.py
File cuối còn xoá 3 bản sao của hàm đã có trong `shared/formatters.py`,
giống hệt đến từng dòng — nay định dạng thời gian và avatar không lệch nhau
giữa các bảng Giám sát nữa.
Docstring
---------
41,6% -> 100% (3.478/3.478 định nghĩa production), kể cả module dormant và
phương thức dunder. Toàn bộ phần bổ sung viết bằng tiếng Việt; comment tiếng
Anh có sẵn giữ nguyên — dịch ngược là một đợt riêng.
Seam chưa nối dây (F-05)
------------------------
9 seam mang nhãn `SEAM · dựng <ngày>` kèm hai câu: được nối khi nào, và để
dormant thì hỏng gì. Ngày lấy từ lịch sử git, không phải hạn tự đặt. Gate O
đọc nhãn đó và nhắc khi quá 30 ngày.
859 test xanh · 4/4 cổng CASAN · 19/24 checker khớp từng byte bản cũ.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+39
-3
@@ -71,6 +71,10 @@ class _EqualTabBar(QTabBar):
|
||||
_GAP = 6 # px between tabs — matches the QSS margin-right below
|
||||
|
||||
def tabSizeHint(self, index): # noqa: N802
|
||||
"""Chia đều bề rộng cho mọi tab thay vì để Qt co theo độ dài nhãn.
|
||||
|
||||
Nhãn dài ngắn khác nhau làm dải tab nhấp nhô mỗi khi đổi tên luồng.
|
||||
"""
|
||||
base = super().tabSizeHint(index)
|
||||
n = self.count() or 1
|
||||
avail = self.width()
|
||||
@@ -81,6 +85,7 @@ class _EqualTabBar(QTabBar):
|
||||
return QSize(max(56, share), max(30, base.height()))
|
||||
|
||||
def resizeEvent(self, e): # noqa: N802
|
||||
"""Đổi bề rộng dải tab thì tính lại bề rộng từng tab."""
|
||||
super().resizeEvent(e)
|
||||
self.updateGeometry() # re-hint tab widths when resized
|
||||
|
||||
@@ -103,9 +108,20 @@ class Co4ETab(
|
||||
Co4ERunsMixin,
|
||||
Co4EChatMixin,
|
||||
QWidget):
|
||||
"""Màn Co4E Studio, ghép từ 7 mixin: dải tab luồng, cột trái, bố cục, CRUD luồng,
|
||||
quản lý agent, chạy luồng, và khung chat.
|
||||
|
||||
Tách thành mixin để mỗi phần nằm trong một file dưới trần 400 dòng; thứ tự
|
||||
kế thừa quan trọng — xem ghi chú ở đầu từng file mixin.
|
||||
"""
|
||||
status_message = Signal(str)
|
||||
|
||||
def __init__(self, ctx):
|
||||
"""Dựng Co4E Studio: khung vẽ workflow, cột nguyên liệu và bảng Flow Status.
|
||||
|
||||
Mở sẵn một workflow trống để người dùng kéo bước vào ngay, không phải bấm
|
||||
"tạo mới" trước.
|
||||
"""
|
||||
super().__init__()
|
||||
self.ctx = ctx
|
||||
self._wf: co4e.Workflow = co4e.new_workflow(tr("co4e.untitled"))
|
||||
@@ -217,9 +233,10 @@ class Co4ETab(
|
||||
# history pane beside it), so the threshold is about its own screen only.
|
||||
_NARROW = 1300
|
||||
|
||||
def showEvent(self, e): # noqa: N802 - Qt override
|
||||
super().showEvent(e)
|
||||
self._narrow_guard.attach()
|
||||
# Chỗ này từng có một ``showEvent`` thứ hai chỉ gọi
|
||||
# ``self._narrow_guard.attach()``. Lớp này còn một ``showEvent`` nữa ở phía
|
||||
# dưới, và Python giữ định nghĩa SAU CÙNG — nên bản ở đây chưa bao giờ chạy.
|
||||
# Đã gộp cả hai việc vào đúng một ``showEvent`` (xem bên dưới).
|
||||
|
||||
|
||||
|
||||
@@ -309,6 +326,7 @@ class Co4ETab(
|
||||
return Path(base) / "co4e"
|
||||
|
||||
def _refresh_ws_folder_btn(self) -> None:
|
||||
"""Cập nhật nhãn nút thư mục làm việc, rút gọn còn hai cấp cuối cho đỡ dài."""
|
||||
root = self._flow_output_root()
|
||||
parts = root.parts
|
||||
short = "…/" + "/".join(parts[-2:]) if len(parts) > 2 else str(root)
|
||||
@@ -316,6 +334,7 @@ class Co4ETab(
|
||||
self.ws_folder_btn.setToolTip(tr("co4e.tt_open_workspace", path=str(root)))
|
||||
|
||||
def _open_workspace_folder(self) -> None:
|
||||
"""Mở thư mục kết quả của luồng trong trình quản lý tệp của hệ điều hành."""
|
||||
from .osutil import open_location
|
||||
root = self._flow_output_root()
|
||||
try:
|
||||
@@ -331,14 +350,26 @@ class Co4ETab(
|
||||
|
||||
|
||||
def showEvent(self, e): # noqa: N802
|
||||
"""Mỗi lần tab được hiện lại: làm mới bảng Flow Status và gắn lại bộ canh
|
||||
bố cục hẹp.
|
||||
|
||||
Gắn lại bộ canh là cần: widget có thể đã được chuyển sang cửa sổ khác kể
|
||||
từ lần hiện trước, và bộ canh theo dõi CỬA SỔ chứ không theo dõi widget.
|
||||
"""
|
||||
# Guarantee the status list is current whenever the tab is shown again.
|
||||
self._refresh_runs()
|
||||
self._narrow_guard.attach()
|
||||
super().showEvent(e)
|
||||
|
||||
def _out_dir(self) -> Path:
|
||||
# Save chat/flow deliverables into the SELECTED workspace (the active
|
||||
# project's folder via _flow_output_root), so files land where the user
|
||||
# works with them — not in the config/install folder.
|
||||
"""Thư mục ghi kết quả của luồng đang mở, tạo sẵn nếu chưa có.
|
||||
|
||||
Ghi vào thư mục của workspace đang chọn để file rơi đúng chỗ người dùng làm
|
||||
việc, không rơi vào thư mục cài đặt.
|
||||
"""
|
||||
d = self._flow_output_root() / co4e.slugify(self._wf.name or "flow")
|
||||
d.mkdir(parents=True, exist_ok=True)
|
||||
return d
|
||||
@@ -359,6 +390,7 @@ class Co4ETab(
|
||||
|
||||
# ---- i18n -------------------------------------------------------------
|
||||
def _retranslate(self) -> None:
|
||||
"""Áp lại chữ theo ngôn ngữ đang chọn cho tiêu đề các mục và tooltip."""
|
||||
for key in self._sections:
|
||||
self._sync_section_arrow(key)
|
||||
self.runs_more_btn.setToolTip(tr("co4e.tt_runs_tab"))
|
||||
@@ -382,9 +414,13 @@ class Co4ETab(
|
||||
|
||||
|
||||
def _html_escape(text: str) -> str:
|
||||
"""Thoát ba ký tự HTML nguy hiểm, để nội dung người dùng không phá vỡ khung chat."""
|
||||
return (text or "").replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
|
||||
|
||||
def _qcolor(hex_str: str):
|
||||
"""Đổi chuỗi màu hex thành ``QColor``. Import muộn để module này nạp được ở nơi
|
||||
chưa có Qt GUI.
|
||||
"""
|
||||
from PySide6.QtGui import QColor
|
||||
return QColor(hex_str)
|
||||
|
||||
Reference in New Issue
Block a user