# #region AssistantToolMigration [C:4] [TYPE Module] [SEMANTICS assistant, tool, migration, execute] # @defgroup AssistantApi Module group. # @BRIEF Handler for the "execute_migration" tool — run dashboard migration between environments. # @LAYER API # @RELATION DEPENDS_ON -> [AssistantToolRegistry] # @RELATION DEPENDS_ON -> [TaskManager] from __future__ import annotations from typing import Any from fastapi import HTTPException from sqlalchemy.orm import Session from src.core.config_manager import ConfigManager from src.core.logger import belief_scope, logger from src.core.task_manager import TaskManager from src.schemas.auth import User from ._history import _coerce_query_bool from ._resolvers import ( _get_environment_name_by_id, _resolve_dashboard_id_entity, _resolve_env_id, ) from ._schemas import AssistantAction from ._tool_registry import _check_any_permission, assistant_tool # #region handle_execute_migration [C:4] [TYPE Function] # @ingroup AssistantApi @assistant_tool( operation="execute_migration", domain="migration", description=( "Run dashboard migration (id/slug/title) between environments. " "Optional boolean flags: replace_db_config, fix_cross_filters" ), required_entities=["source_env", "target_env"], optional_entities=[ "dashboard_id", "dashboard_ref", "replace_db_config", "fix_cross_filters", ], risk_level="guarded", requires_confirmation=False, permission_checks=[ ("plugin:migration", "EXECUTE"), ("plugin:superset-migration", "EXECUTE"), ], ) @belief_scope("execute_migration") async def handle_execute_migration( intent: dict[str, Any], current_user: User, task_manager: TaskManager, config_manager: ConfigManager, db: Session, ) -> tuple[str, str | None, list[AssistantAction]]: """Run dashboard migration between environments.""" _check_any_permission( current_user, [("plugin:migration", "EXECUTE"), ("plugin:superset-migration", "EXECUTE")], ) entities = intent.get("entities", {}) src_token = entities.get("source_env") dashboard_ref = entities.get("dashboard_ref") dashboard_id = await _resolve_dashboard_id_entity( entities, config_manager, env_hint=src_token ) src = _resolve_env_id(src_token, config_manager) tgt = _resolve_env_id(entities.get("target_env"), config_manager) if not src or not tgt: raise HTTPException(status_code=422, detail="Missing source_env/target_env") if not dashboard_id and (not dashboard_ref): raise HTTPException(status_code=422, detail="Missing dashboard_id/dashboard_ref") migration_params: dict[str, Any] = { "source_env_id": src, "target_env_id": tgt, "replace_db_config": _coerce_query_bool( entities.get("replace_db_config", False) ), "fix_cross_filters": _coerce_query_bool( entities.get("fix_cross_filters", True) ), } if dashboard_id: migration_params["selected_ids"] = [dashboard_id] else: migration_params["dashboard_regex"] = str(dashboard_ref) task = await task_manager.create_task( plugin_id="superset-migration", params=migration_params, user_id=current_user.id, ) actions: list[AssistantAction] = [ AssistantAction(type="open_task", label="Open Task", target=task.id), AssistantAction( type="open_reports", label="Open Reports", target="/reports" ), ] if dashboard_id: actions.append( AssistantAction( type="open_route", label=f"Открыть дашборд в {_get_environment_name_by_id(tgt, config_manager)}", target=f"/dashboards/{dashboard_id}?env_id={tgt}", ) ) actions.append( AssistantAction( type="open_diff", label="Показать Diff", target=str(dashboard_id) ) ) return (f"Миграция запущена. task_id={task.id}", task.id, actions) # #endregion handle_execute_migration # #endregion AssistantToolMigration