# #region AssistantToolSearchDashboards [C:3] [TYPE Module] [SEMANTICS assistant, tool, dashboards, search] # @defgroup AssistantApi Module group. # @BRIEF Handler for the "search_dashboards" tool — search and list dashboards from an environment. # @LAYER API # @RELATION DEPENDS_ON -> [AssistantToolRegistry] # @RELATION DEPENDS_ON -> [SupersetClient] from __future__ import annotations from typing import Any from sqlalchemy.orm import Session from src.core.config_manager import ConfigManager from src.core.logger import belief_scope, logger from src.core.superset_client import SupersetClient from src.core.task_manager import TaskManager from src.schemas.auth import User from ._resolvers import _resolve_env_id from ._schemas import AssistantAction from ._tool_registry import assistant_tool # #region handle_search_dashboards [C:3] [TYPE Function] # @ingroup AssistantApi @assistant_tool( operation="search_dashboards", domain="dashboards", description="Search and list dashboards by name/id from an environment. Shows id, title, and URL for each dashboard.", optional_entities=["environment", "search", "page", "page_size"], risk_level="safe", requires_confirmation=False, ) @belief_scope("search_dashboards") async def handle_search_dashboards( intent: dict[str, Any], current_user: User, task_manager: TaskManager, config_manager: ConfigManager, db: Session, ) -> tuple[str, str | None, list[AssistantAction]]: """Search and list dashboards from an environment.""" entities = intent.get("entities", {}) env_token = entities.get("environment") search = entities.get("search") page = int(entities.get("page", 1)) page_size = min(int(entities.get("page_size", 20)), 100) env_id = _resolve_env_id(env_token, config_manager) if not env_id: # Show available environments if none specified envs = config_manager.get_environments() if not envs: return ("Нет доступных окружений.", None, []) env_list = "\n".join(f"- {e.id} ({e.name})" for e in envs) return ( f"Укажите окружение. Доступные:\n{env_list}\n\n" f"Пример: `покажи дашборды из окружения dev`", None, [], ) env_map = {e.id: e for e in config_manager.get_environments()} env = env_map.get(env_id) if not env: return (f"Окружение {env_id} не найдено.", None, []) client = SupersetClient(env) all_dashboards = await client.get_dashboards_summary(require_slug=True) # Filter by search term if search: search_lower = search.lower() filtered = [ d for d in all_dashboards if search_lower in str(d.get("id", "")) or search_lower in str(d.get("title", "")).lower() or search_lower in str(d.get("slug", "")).lower() ] else: filtered = list(all_dashboards) total = len(filtered) start = (page - 1) * page_size page_items = filtered[start : start + page_size] if not page_items: if search: return ( f"Дашборды по запросу «{search}» в окружении {env.name} не найдены.", None, [], ) return (f"В окружении {env.name} нет дашбордов.", None, []) lines = [f"📊 Дашборды в окружении **{env.name}** ({total} всего):"] for d in page_items: title = d.get("title", "Без названия") did = d.get("id", "?") slug = d.get("slug", "") slug_str = f" ({slug})" if slug else "" lines.append(f"- #{did} {title}{slug_str}") if start + page_size < total: lines.append(f"\n... и ещё {total - start - page_size}") actions = [ AssistantAction( type="open_route", label=f"Открыть дашборды в {env.name}", target=f"/dashboards?env_id={env_id}", ) ] return ("\n".join(lines), None, actions) # #endregion handle_search_dashboards # #endregion AssistantToolSearchDashboards