"""
Dashboards Handler - Dashboards & Panels
Phase J.4: 8 tools
- Dashboards: list, get, create, update, delete (5)
- Panels: list, create, delete (3)
"""
import json
from typing import Any
from plugins.directus.client import DirectusClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator (8 tools)"""
return [
# =====================
# DASHBOARDS (5)
# =====================
{
"name": "list_dashboards",
"method_name": "list_dashboards",
"description": "List all insights dashboards.",
"schema": {
"type": "object",
"properties": {
"filter": {
"anyOf": [{"type": "object"}, {"type": "null"}],
"description": "Filter object",
},
"sort": {
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
"description": "Sort fields",
},
"limit": {
"type": "integer",
"description": "Maximum dashboards to return",
"default": 100,
},
},
"required": [],
},
"scope": "read",
},
{
"name": "get_dashboard",
"method_name": "get_dashboard",
"description": "Get dashboard details by ID.",
"schema": {
"type": "object",
"properties": {"id": {"type": "string", "description": "Dashboard UUID"}},
"required": ["id"],
},
"scope": "read",
},
{
"name": "create_dashboard",
"method_name": "create_dashboard",
"description": "Create a new insights dashboard.",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string", "description": "Dashboard name"},
"icon": {
"type": "string",
"description": "Material icon",
"default": "dashboard",
},
"note": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Dashboard description",
},
"color": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Accent color",
},
},
"required": ["name"],
},
"scope": "write",
},
{
"name": "update_dashboard",
"method_name": "update_dashboard",
"description": "Update dashboard settings.",
"schema": {
"type": "object",
"properties": {
"id": {"type": "string", "description": "Dashboard UUID"},
"data": {
"type": "object",
"description": "Fields to update (name, icon, note, color)",
},
},
"required": ["id", "data"],
},
"scope": "write",
},
{
"name": "delete_dashboard",
"method_name": "delete_dashboard",
"description": "Delete a dashboard and its panels.",
"schema": {
"type": "object",
"properties": {"id": {"type": "string", "description": "Dashboard UUID to delete"}},
"required": ["id"],
},
"scope": "write",
},
# =====================
# PANELS (3)
# =====================
{
"name": "list_panels",
"method_name": "list_panels",
"description": "List all panels, optionally filtered by dashboard.",
"schema": {
"type": "object",
"properties": {
"filter": {
"anyOf": [{"type": "object"}, {"type": "null"}],
"description": 'Filter object (e.g., {"dashboard": {"_eq": "dashboard-uuid"}})',
},
"limit": {
"type": "integer",
"description": "Maximum panels to return",
"default": 100,
},
},
"required": [],
},
"scope": "read",
},
{
"name": "create_panel",
"method_name": "create_panel",
"description": "Create a new panel in a dashboard.",
"schema": {
"type": "object",
"properties": {
"dashboard": {"type": "string", "description": "Dashboard UUID"},
"type": {
"type": "string",
"description": "Panel type (label, list, metric, time-series, etc.)",
},
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Panel name",
},
"icon": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Material icon",
},
"color": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Accent color",
},
"note": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Panel description",
},
"width": {
"type": "integer",
"description": "Panel width (1-12 grid units)",
"default": 12,
},
"height": {
"type": "integer",
"description": "Panel height (grid units)",
"default": 6,
},
"position_x": {
"type": "integer",
"description": "X position in dashboard",
"default": 0,
},
"position_y": {
"type": "integer",
"description": "Y position in dashboard",
"default": 0,
},
"options": {
"anyOf": [{"type": "object"}, {"type": "null"}],
"description": "Panel-specific options",
},
},
"required": ["dashboard", "type"],
},
"scope": "write",
},
{
"name": "delete_panel",
"method_name": "delete_panel",
"description": "Delete a panel from a dashboard.",
"schema": {
"type": "object",
"properties": {"id": {"type": "string", "description": "Panel UUID to delete"}},
"required": ["id"],
},
"scope": "write",
},
]
# =====================
# HANDLER FUNCTIONS
# =====================
async def list_dashboards(
client: DirectusClient,
filter: dict | None = None,
sort: list[str] | None = None,
limit: int = 100,
) -> str:
"""List dashboards."""
try:
result = await client.list_dashboards(filter=filter, sort=sort, limit=limit)
dashboards = result.get("data", [])
return json.dumps(
{"success": True, "total": len(dashboards), "dashboards": dashboards},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def get_dashboard(client: DirectusClient, id: str) -> str:
"""Get dashboard by ID."""
try:
result = await client.get_dashboard(id)
return json.dumps(
{"success": True, "dashboard": result.get("data")}, indent=2, ensure_ascii=False
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def create_dashboard(
client: DirectusClient,
name: str,
icon: str = "dashboard",
note: str | None = None,
color: str | None = None,
) -> str:
"""Create a new dashboard."""
try:
result = await client.create_dashboard(name=name, icon=icon, note=note, color=color)
return json.dumps(
{
"success": True,
"message": f"Dashboard '{name}' created",
"dashboard": result.get("data"),
},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def update_dashboard(client: DirectusClient, id: str, data: dict[str, Any]) -> str:
"""Update dashboard."""
try:
result = await client.update_dashboard(id, data)
return json.dumps(
{"success": True, "message": "Dashboard updated", "dashboard": result.get("data")},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def delete_dashboard(client: DirectusClient, id: str) -> str:
"""Delete a dashboard."""
try:
await client.delete_dashboard(id)
return json.dumps({"success": True, "message": f"Dashboard {id} deleted"}, indent=2)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def list_panels(client: DirectusClient, filter: dict | None = None, limit: int = 100) -> str:
"""List panels."""
try:
result = await client.list_panels(filter=filter, limit=limit)
panels = result.get("data", [])
return json.dumps(
{"success": True, "total": len(panels), "panels": panels}, indent=2, ensure_ascii=False
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def create_panel(
client: DirectusClient,
dashboard: str,
type: str,
name: str | None = None,
icon: str | None = None,
color: str | None = None,
note: str | None = None,
width: int = 12,
height: int = 6,
position_x: int = 0,
position_y: int = 0,
options: dict | None = None,
) -> str:
"""Create a new panel."""
try:
result = await client.create_panel(
dashboard=dashboard,
type=type,
name=name,
icon=icon,
color=color,
note=note,
width=width,
height=height,
position_x=position_x,
position_y=position_y,
options=options,
)
return json.dumps(
{"success": True, "message": f"Panel '{type}' created", "panel": result.get("data")},
indent=2,
ensure_ascii=False,
)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)
async def delete_panel(client: DirectusClient, id: str) -> str:
"""Delete a panel."""
try:
await client.delete_panel(id)
return json.dumps({"success": True, "message": f"Panel {id} deleted"}, indent=2)
except Exception as e:
return json.dumps({"success": False, "error": str(e)}, indent=2)