"""Nhập task từ file — R08-T11. Tab thứ hai của hộp thoại tạo task: tải mẫu về, điền, rồi kéo file vào hoặc chọn từ máy. Xem trước nội dung đọc được trước khi tạo, vì một file sai định dạng có thể sinh ra hàng chục task rác. Là mixin chứ không phải hộp thoại rời: nó dùng chung phần xem trước và nút Xác nhận với tab tạo bằng AI, tách hẳn thì phải nhân đôi cả hai. """ from __future__ import annotations import copy from pathlib import Path from typing import Dict, List, Optional from PySide6.QtCore import Qt, Signal from PySide6.QtWidgets import ( QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QMenu, QMessageBox, QPlainTextEdit, QPushButton, QScrollArea, QSizePolicy, QStackedWidget, QTabBar, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, ) from ...core import tasks as taskrepo from ...core.projects import list_projects from ...core.tasks import STATUSES, chain_error, duplicate_task, new_task from ...core.worker import AgentWorker from ...i18n import on_language_changed, tr from ...state import AppContext from ...theme import current_palette from ...ui.calendar_view import CalendarView from ...ui.icons import icon from ...ui.osutil import open_path from .kanban_board_widget import _DropZone class TaskImportMixin: """Nhập task từ file. Trộn vào _AiCreateDialog.""" def _export_template(self) -> None: from PySide6.QtWidgets import QFileDialog from ..core.task_excel import export_template path, _ = QFileDialog.getSaveFileName( self, tr("schedtask.export_template_btn"), "cowork_tasks_template.xlsx", "Excel (*.xlsx)") if not path: return try: export_template(path) open_path(str(Path(path).parent)) except Exception as exc: # noqa: BLE001 QMessageBox.warning(self, tr("schedtask.tab_import"), str(exc)) def _pick_import_file(self) -> None: from PySide6.QtWidgets import QFileDialog from ..core.task_import import IMPORT_FILTER path, _ = QFileDialog.getOpenFileName( self, tr("schedtask.import_pick_btn"), "", IMPORT_FILTER) if path: self._load_import_file(path) def _load_import_file(self, path: str) -> None: from ..core.task_import import import_tasks try: self._planned = import_tasks(path) except ValueError as exc: self.import_preview.setPlainText(str(exc)) self.buttons.button(QDialogButtonBox.Ok).setEnabled(False) return by_id = {t["task_id"]: t["title"] for t in self._planned} lines = [] for i, t in enumerate(self._planned, 1): sched = t.get("schedule", {}) when = sched.get("run_at") if sched.get("enabled") else tr("schedtask.no_schedule") deps = t.get("dependency", {}).get("depends_on") or [] dep_note = (" ← depends: " + ", ".join(by_id.get(d, "?") for d in deps)) if deps else "" lines.append(f"{i}. [{t.get('task_type')}] {t.get('title')}\n" f" {when} repeat={sched.get('repeat_type', 'none')}{dep_note}") self.import_preview.setPlainText("\n\n".join(lines)) self.buttons.button(QDialogButtonBox.Ok).setEnabled(bool(self._planned))