InstantMCP / ui_components /admin_panel.py
areeb1501
Fix deployment filtering, remove stats mode, add tab width CSS
8e72089
"""
Admin Panel UI Component
Interactive UI for managing MCP server deployments.
"""
import gradio as gr
from mcp_tools.deployment_tools import (
deploy_mcp_server,
list_deployments,
delete_deployment,
get_deployment_status
)
def create_admin_panel():
"""
Create the admin panel UI component.
Returns:
gr.Blocks: Admin panel interface
"""
with gr.Blocks() as panel:
gr.Markdown("## ⚙️ Deployment Management")
gr.Markdown("Deploy and manage your MCP servers")
# Quick Deploy Section
with gr.Accordion("➕ Quick Deploy", open=True):
with gr.Row():
with gr.Column(scale=2):
server_name = gr.Textbox(
label="Server Name",
placeholder="my-mcp-server",
info="Unique name for your MCP server"
)
code = gr.Code(
language="python",
label="MCP Tools Code",
lines=12,
value='''from fastmcp import FastMCP
mcp = FastMCP("cat-facts")
@mcp.tool()
def get_cat_fact() -> str:
"""Get a random cat fact from an API"""
import requests
response = requests.get("https://catfact.ninja/fact")
return response.json()["fact"]
@mcp.tool()
def add_numbers(a: int, b: int) -> int:
"""Add two numbers together"""
return a + b
'''
)
with gr.Column(scale=1):
packages = gr.Textbox(
label="Extra Packages",
placeholder="requests, pandas",
value="requests",
info="Comma-separated pip packages"
)
description = gr.Textbox(
label="Description",
lines=2,
placeholder="Optional description"
)
# New metadata fields
with gr.Row():
category = gr.Textbox(
label="Category",
placeholder="e.g., Weather, Finance",
value="Uncategorized",
scale=1
)
version = gr.Textbox(
label="Version",
value="1.0.0",
scale=1
)
tags = gr.Textbox(
label="Tags (comma-separated)",
placeholder="e.g., api, data, utilities"
)
author = gr.Textbox(
label="Author",
value="Anonymous"
)
deploy_btn = gr.Button("🚀 Deploy", variant="primary", size="lg")
deploy_output = gr.JSON(label="Deployment Result")
# Helper function to parse tags
def deploy_with_metadata(name, code_val, pkgs, desc, cat, tag_str, auth, ver):
"""Deploy with metadata, parsing tags from comma-separated string"""
tag_list = [t.strip() for t in tag_str.split(",") if t.strip()] if tag_str else []
return deploy_mcp_server(
server_name=name,
mcp_tools_code=code_val,
extra_pip_packages=pkgs,
description=desc,
category=cat,
tags=tag_list,
author=auth,
version=ver
)
# Wire up deploy button
deploy_btn.click(
fn=deploy_with_metadata,
inputs=[server_name, code, packages, description, category, tags, author, version],
outputs=deploy_output,
api_visibility="private" # Don't expose UI handler as MCP tool
)
# Deployments Table Section
gr.Markdown("### 📋 Active Deployments")
with gr.Row():
refresh_btn = gr.Button("🔄 Refresh", size="sm", scale=0)
search_box = gr.Textbox(
label="Search",
placeholder="Filter by name...",
scale=2
)
category_filter = gr.Dropdown(
label="Filter by Category",
choices=["All Categories"],
value="All Categories",
scale=1
)
deployments_df = gr.Dataframe(
headers=["ID", "Name", "Category", "Tags", "Version", "Author", "Status", "Created"],
datatype=["str", "str", "str", "str", "str", "str", "str", "str"],
interactive=False,
wrap=True,
label="Deployments"
)
# Quick Actions Section
with gr.Accordion("⚡ Quick Actions", open=False):
with gr.Row():
deployment_selector = gr.Dropdown(
label="Select Deployment",
choices=[],
interactive=True
)
action_selector = gr.Dropdown(
label="Action",
choices=["View Status", "Delete (confirm required)"],
value="View Status",
interactive=True
)
execute_btn = gr.Button("Execute", variant="secondary")
action_output = gr.JSON(label="Action Result")
# Functions
def load_deployments():
"""Load all deployments into the table"""
result = list_deployments()
if result["success"]:
data = []
dropdown_choices = []
categories = set(["All Categories"])
for dep in result["deployments"]:
# Format tags
tags_str = ", ".join(dep.get("tags", [])) if dep.get("tags") else "—"
data.append([
dep.get("deployment_id", "")[:16] + "...", # Shortened ID
dep.get("server_name", "Unknown"),
dep.get("category", "Uncategorized"),
tags_str,
dep.get("version", "1.0.0"),
dep.get("author", "Anonymous"),
dep.get("status", "unknown"),
dep.get("created_at", "")[:10] if dep.get("created_at") else "N/A" # Date only
])
dropdown_choices.append(
(dep["server_name"], dep["deployment_id"])
)
# Collect unique categories
if dep.get("category"):
categories.add(dep["category"])
return data, gr.Dropdown(choices=dropdown_choices), gr.Dropdown(choices=sorted(list(categories)))
return [], gr.Dropdown(choices=[]), gr.Dropdown(choices=["All Categories"])
def execute_action(deployment_id, action):
"""Execute selected action on deployment"""
if not deployment_id:
return {"success": False, "error": "Select a deployment first"}
if "Delete" in action:
return delete_deployment(deployment_id=deployment_id, confirm=True)
elif "View Status" in action:
return get_deployment_status(deployment_id=deployment_id)
return {"success": False, "error": "Unknown action"}
def filter_deployments(search_term, category_val):
"""Filter deployments by search term and category"""
result = list_deployments()
if not result["success"]:
return []
filtered_data = []
for dep in result["deployments"]:
# Check search term
search_match = (not search_term or
search_term.lower() in dep["server_name"].lower() or
search_term.lower() in dep["deployment_id"].lower())
# Check category filter
category_match = (category_val == "All Categories" or
dep.get("category", "Uncategorized") == category_val)
if search_match and category_match:
tags_str = ", ".join(dep.get("tags", [])) if dep.get("tags") else "—"
filtered_data.append([
dep.get("deployment_id", "")[:16] + "...",
dep.get("server_name", "Unknown"),
dep.get("category", "Uncategorized"),
tags_str,
dep.get("version", "1.0.0"),
dep.get("author", "Anonymous"),
dep.get("status", "unknown"),
dep.get("created_at", "")[:10] if dep.get("created_at") else "N/A"
])
return filtered_data
# Wire up events
refresh_btn.click(
fn=load_deployments,
outputs=[deployments_df, deployment_selector, category_filter],
api_visibility="private" # Don't expose UI handler as MCP tool
)
search_box.change(
fn=filter_deployments,
inputs=[search_box, category_filter],
outputs=deployments_df,
api_visibility="private" # Don't expose UI handler as MCP tool
)
category_filter.change(
fn=filter_deployments,
inputs=[search_box, category_filter],
outputs=deployments_df,
api_visibility="private" # Don't expose UI handler as MCP tool
)
execute_btn.click(
fn=execute_action,
inputs=[deployment_selector, action_selector],
outputs=action_output,
api_visibility="private" # Don't expose UI handler as MCP tool
)
# Load deployments on panel load
panel.load(
fn=load_deployments,
outputs=[deployments_df, deployment_selector, category_filter],
api_visibility="private" # Don't expose UI handler as MCP tool
)
return panel