Sau khi đường dẫn trên thanh đã trỏ đúng thư mục mới, các node giữa màn vẫn là
của thư mục cũ: không có lệnh quét lại nào được phát ra.
Cùng một họ sai lầm với hai mảnh trước — câu hỏi "có gì đổi không" trả lời bằng
project id chứ không bằng thứ quyết định kết quả quét:
project_changed = pid != self._active_project_id
Đổi thư mục giữ nguyên id, nên project_changed là False và cả khối phát tín
hiệu lẫn khối gọi _scan() đều bị bỏ qua, trong khi dòng đặt path_edit lại nằm
ngoài khối đó — thanh địa chỉ đúng mà đồ thị đứng yên.
Tách khối "project sandbox lock" sang graph_project_lock.py: graph_renderer.py
đang ở 399/400 dòng, đúng một dòng trước trần của scripts/check_loc.py, và cổng
đó nói rõ cách duy nhất đúng khi chạm trần là tách file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
4.1 KiB
Python
84 lines
4.1 KiB
Python
"""Khoá phạm vi quét của màn GraphRAG vào một project.
|
|
|
|
Tách khỏi ``graph_renderer.py``: file đó đã ở 399/400 dòng — đúng một dòng
|
|
trước trần của ``scripts/check_loc.py``, và cổng ấy nói rõ cách duy nhất đúng
|
|
khi chạm trần là tách file, không phải nới con số. Khối này là chỗ tự nhiên
|
|
để cắt: ba phương thức dưới đây chỉ nói về một việc — project nào đang khoá,
|
|
và thư mục nào đi theo nó — còn phần còn lại của renderer lo việc vẽ.
|
|
|
|
Là mixin chứ không phải đối tượng rời, cùng lý do như ``NavRailMixin``: ba
|
|
phương thức này đọc/ghi state của chính renderer (``project_combo``,
|
|
``path_edit``, ``_needs_scan``…). Biến thành đối tượng cộng tác thì phải viết
|
|
lại từng chỗ ``self.X`` thành ``self.renderer.X`` mà không đổi hành vi gì.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from cowork_local.i18n import tr
|
|
|
|
|
|
class GraphProjectLockMixin:
|
|
"""Ba phương thức khoá-theo-project. Trộn vào ``GraphRenderer``."""
|
|
|
|
def _refresh_project_combo(self) -> None:
|
|
"""Nạp lại danh sách project vào bộ chọn, giữ nguyên project đang chọn."""
|
|
from cowork_local.core.projects import list_projects
|
|
|
|
keep = self._active_project_id
|
|
self.project_combo.blockSignals(True)
|
|
self.project_combo.clear()
|
|
self.project_combo.addItem(tr("structure.project_none"), "")
|
|
row_to_select = 0
|
|
for i, p in enumerate(list_projects(), start=1):
|
|
self.project_combo.addItem(p.name, p.project_id)
|
|
if p.project_id == keep:
|
|
row_to_select = i
|
|
self.project_combo.setCurrentIndex(row_to_select)
|
|
self.project_combo.blockSignals(False)
|
|
|
|
def set_project(self, project_id: str) -> None:
|
|
"""Khoá phạm vi quét vào một project (chuỗi rỗng là bỏ khoá)."""
|
|
pid = project_id or ""
|
|
self._refresh_project_combo()
|
|
target = self.project_combo.findData(pid)
|
|
if target < 0:
|
|
target = 0
|
|
if self.project_combo.currentIndex() == target:
|
|
self._on_project_changed(target)
|
|
else:
|
|
self.project_combo.setCurrentIndex(target)
|
|
|
|
def _on_project_changed(self, _idx: int) -> None:
|
|
"""Áp trạng thái khoá: đường dẫn chuyển sang chỉ đọc và trỏ vào thư mục"""
|
|
from cowork_local.core.projects import load_project
|
|
|
|
pid = self.project_combo.currentData() or ""
|
|
project_changed = pid != self._active_project_id
|
|
self._active_project_id = pid
|
|
locked = bool(pid)
|
|
self.path_edit.setReadOnly(locked)
|
|
self._pick_btn.setEnabled(not locked)
|
|
if locked:
|
|
project = load_project(pid)
|
|
if project is not None:
|
|
self.path_edit.setText(str(project.workspace_dir()))
|
|
# Changing the FOLDER changes what we scan just as much as changing the
|
|
# project does. Keying this off the id alone left the path in the bar
|
|
# updated while the graph in the middle still showed the old folder's
|
|
# nodes: "Đổi" in the Project screen moves the folder, never the id.
|
|
duong_dan = self.path_edit.text().strip()
|
|
doi_muc_tieu = project_changed or duong_dan != self._active_path
|
|
self._active_path = duong_dan
|
|
if doi_muc_tieu:
|
|
self.project_changed.emit() # GraphQaWidget drops its temp extraction cache
|
|
# Mark it and scan on the next visit rather than now — see
|
|
# auto_scan_and_fit()'s docstring for why.
|
|
self._needs_scan = True
|
|
# ...except when this screen is the one on show. The picker lives HERE,
|
|
# so a user changing project is already looking at the graph: there is
|
|
# no "next visit" to defer to, and they had to press Scan by hand.
|
|
# Deferring still applies when the change came from the Workspace
|
|
# screen while this one is hidden, which is what it was for.
|
|
if self.isVisible() and duong_dan:
|
|
self._needs_scan = False
|
|
self._scan()
|