"""Workspace UI extension API. No model or device actions are dispatched.""" from uuid import UUID from fastapi import APIRouter, HTTPException from pydantic import BaseModel, ConfigDict, Field from apps.admin_console.services import batch_archive, report_export, task_extensions from apps.admin_console.services.automation_store import store router = APIRouter(prefix="/api/task-extensions", tags=["task-extensions"]) class ExtensionUpdate(BaseModel): model_config = ConfigDict(extra="forbid") values: dict[str, str] = Field(max_length=20) expected_revision: int = Field(ge=0) request_id: UUID @router.get("/{session_id}") def read_extensions(session_id: str): try: return { **task_extensions.task_context(session_id, store), "plugins": task_extensions.contributions(session_id, store), } except ValueError as exc: raise HTTPException(404, str(exc)) from exc @router.put("/{session_id}/{plugin_id}") def update_extension(session_id: str, plugin_id: str, value: ExtensionUpdate): job = store.job(session_id) or {} batch_id = job.get("batch_id") if ( batch_id and batch_archive.status(batch_id, store.get("batch", batch_id) or {})["status"] == "preparing" ): raise HTTPException(409, "报告正在打包,请稍后保存评审") with ( report_export.export_lock( *(["batch:" + batch_id] if batch_id else []), "session:" + session_id ), task_extensions.plugin_store().mutation_lock, ): context = read_extensions(session_id) if not context["editable"]: raise HTTPException(409, "请在任务结束后填写评审") manifest = next((m for m in task_extensions.active_manifests() if m.id == plugin_id), None) if manifest is None: raise HTTPException(409, "插件未安装或未启用,请刷新页面") try: task_extensions.save_values( store, session_id, manifest, value.values, value.expected_revision, str(value.request_id), ) except ValueError as exc: raise HTTPException(409, str(exc)) from exc if batch_id: batch_archive.forget(batch_id) return read_extensions(session_id)