Files
cowork-local/presentation/co4e/skills_list_panel.py
T
lamhv7andClaude Sonnet 5 0631abf85f feat(co4e): tách 6 widget UI khỏi ui/co4e_tab.py sang presentation/co4e/*
Lane N3 (Co4E Studio) — dùng bộ workflow refactor-god-file, mỗi bước có
characterization test trước khi tách, hậu kiểm ranh giới tầng sau mỗi bước:

- skills_list_panel.py / agent_list_panel.py — 2 khu vực sidebar
- co4e_canvas_widget.py + canvas_items.py + canvas_interaction_mixin.py —
  Co4ECanvas tách 3 file (vượt 400 dòng nếu đứng một mình)
- node_property_panel.py + node_property_actions_mixin.py +
  step_config_section.py — StepConfigPanel, cùng lý do
- co4e_run_control_widget.py — RunsPagePanel (trang Flow Status)
- co4e_chat_view.py — ChatPanel + _ChatInput + helper autocomplete
- palette_list.py — _PaletteList dời khỏi ui/co4e_tab.py, hết import ngược
  presentation -> ui (agent/skills panel giờ import top-level)

ui/co4e_tab.py giảm 2089 -> 1878 dòng, chỉ còn phần wiring + business logic
(Co4ERunManager/AgentWorker chưa đổi — nằm ngoài phạm vi này, xem docstring
presentation/co4e/co4e_tab.py). ui/co4e_canvas.py và ui/co4e_config_panel.py
còn lại là compat shim re-export, không đổi API cho bên gọi.

Thêm tests/test_co4e_integration.py — dựng thật Co4ETab qua build_co4e_tab(),
lái luồng qua nhiều panel trong cùng instance (thêm node, mở/gập chat, chuyển
trang Flow Status rồi quay lại không mất state canvas) — bắt lỗi wiring
xuyên-panel mà characterization test từng panel riêng không thấy được.

Đã xác minh: pytest 348 passed/1 skipped, tools/check_co4e.py sạch, không
file nào >400 dòng, domain/application không import PySide6, và so pixel
before/after (git worktree tại HEAD cũ) ra 0/1.125.000 pixel khác biệt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 18:43:42 +09:00

60 lines
3.2 KiB
Python

"""Panel khu vực SKILLS của sidebar Co4E — tách khỏi ``ui/co4e_tab.py``.
Vấn đề đang có: ``ui/co4e_tab.py`` đang gộp việc dựng widget (nút "Quản lý
skill" + danh sách kéo-thả) ngay bên trong thân hàm dựng cả cột sidebar,
khiến file đó (2000+ dòng) khó đọc và khó giữ dưới giới hạn CASAN (≤400 dòng
mỗi file production). Đoạn dựng widget khu vực SKILLS (nguyên bản ở
``ui/co4e_tab.py`` dòng 569-580) không phụ thuộc phần còn lại của
``Co4ETab`` — nó chỉ tạo ``QPushButton`` + ``_PaletteList`` + layout bọc — nên
tách được thành một ``QWidget`` con độc lập.
Cách làm: dời nguyên phần dựng widget sang đây, KHÔNG đổi tên thuộc tính so
với bản gốc (``sk_manage_btn`` → ``manage_btn``, ``skill_list`` →
``list_widget``, chỉ đổi TÊN THUỘC TÍNH cho khớp quy ước panel công khai, còn
giá trị/thứ tự dựng/không dựng gì thêm thì giữ y hệt). Panel KHÔNG tự nối
``.clicked`` của ``manage_btn`` và KHÔNG tự gọi ``_reload_sidebar`` — theo
đúng nguyên tắc "một việc rẽ ra một lần": việc dựng widget (ở đây) tách khỏi
việc nối hành vi (vẫn ở ``Co4ETab``, nơi biết ``_manage_skills`` là gì). Gộp
hai việc đó vào panel sẽ buộc panel phải biết về ``Co4ETab``, xoá mất lý do
tách nó ra.
Cập nhật 25/08: ``_PaletteList`` đã dời khỏi ``ui/co4e_tab.py`` sang
``presentation/co4e/palette_list.py`` (module dùng chung, không phụ thuộc
``ui/``) — import thẳng ở top-level như bên dưới, không còn cần deferred-import
né vòng lặp nữa (xem docstring đầu ``presentation/co4e/palette_list.py`` để
biết lý do dời).
"""
from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QPushButton, QVBoxLayout, QWidget
from ...i18n import tr
from .palette_list import _PaletteList
class SkillsListPanel(QWidget):
"""Widget khu vực SKILLS của sidebar Co4E: nút quản lý + danh sách kéo-thả.
Vai trò: một widget con thuần ở tầng presentation, chỉ dựng cấu trúc UI
(đúng những gì ``ui/co4e_tab.py`` dòng 569-580 làm trước đây), không biết
gì về ``Co4ETab``/``_manage_skills``/``_reload_sidebar``. Bên gọi (hiện là
``Co4ETab``) tự đọc ``.manage_btn``/``.list_widget`` để nối signal và nạp
dữ liệu — panel không tự làm hộ, để giữ đúng ranh giới "một nơi một việc".
"""
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.manage_btn = QPushButton(tr("co4e.manage_skills"))
self.manage_btn.setToolTip(tr("co4e.tt_manage_skills"))
self.manage_btn.setObjectName("co4eSectionAction")
self.manage_btn.setFlat(True)
self.manage_btn.setCursor(Qt.PointingHandCursor)
# KHONG noi .clicked o day: ben goi (Co4ETab) tu quyet dinh slot nao
# xu ly - panel chi dung widget, khong biet _manage_skills la gi.
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(4)
self.list_widget = _PaletteList()
layout.addWidget(self.list_widget, 1)