feat(settings): implement Tools tab with detail drawer

Replaces stub ToolsTab with a grouped-by-module grid of clickable tool cards.
Adds ToolDetailDrawer (Sheet) showing name, description, module, source_location,
and params_schema for the selected tool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 06:50:08 +00:00
parent f418686724
commit 7e3c912899
2 changed files with 148 additions and 1 deletions

View File

@@ -0,0 +1,65 @@
"use client";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
} from "@/components/ui/sheet";
import { Badge } from "@/components/ui/badge";
import type { McpTool } from "@/lib/api/settings";
type Props = {
tool: McpTool | null;
open: boolean;
onOpenChange: (o: boolean) => void;
};
export function ToolDetailDrawer({ tool, open, onOpenChange }: Props) {
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent side="left" className="sm:max-w-xl overflow-y-auto">
{tool && (
<>
<SheetHeader>
<SheetTitle dir="ltr" className="font-mono text-navy">
{tool.name}
</SheetTitle>
<SheetDescription>{tool.description || "—"}</SheetDescription>
</SheetHeader>
<div className="space-y-4 mt-4 px-4 pb-6">
<div>
<div className="text-[0.72rem] text-ink-muted uppercase mb-1">
Module
</div>
<Badge variant="outline" className="font-mono" dir="ltr">
{tool.module}
</Badge>
</div>
<div>
<div className="text-[0.72rem] text-ink-muted uppercase mb-1">
Source
</div>
<code dir="ltr" className="text-xs text-ink break-all">
{tool.source_location || "—"}
</code>
</div>
<div>
<div className="text-[0.72rem] text-ink-muted uppercase mb-1">
Parameters Schema
</div>
<pre
dir="ltr"
className="text-xs bg-rule-soft/40 border border-rule rounded-md p-3 overflow-x-auto"
>
{JSON.stringify(tool.params_schema, null, 2)}
</pre>
</div>
</div>
</>
)}
</SheetContent>
</Sheet>
);
}

View File

@@ -1 +1,83 @@
export function ToolsTab() { return <div>Tools tab coming soon</div>; }
"use client";
import { useState, useMemo } from "react";
import { Wrench, AlertCircle } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Badge } from "@/components/ui/badge";
import { useMcpTools, type McpTool } from "@/lib/api/settings";
import { ToolDetailDrawer } from "./tool-detail-drawer";
export function ToolsTab() {
const { data, isPending, error } = useMcpTools();
const [selected, setSelected] = useState<McpTool | null>(null);
const [open, setOpen] = useState(false);
const grouped = useMemo(() => {
if (!data?.tools) return new Map<string, McpTool[]>();
const m = new Map<string, McpTool[]>();
for (const t of data.tools) {
const mod = t.module.split(".").pop() || "other";
const arr = m.get(mod) ?? [];
arr.push(t);
m.set(mod, arr);
}
return m;
}, [data]);
if (isPending) return <Skeleton className="h-96 w-full" />;
if (error) {
return (
<Card className="bg-surface border-danger/40">
<CardContent className="p-6 flex items-center gap-3 text-danger">
<AlertCircle className="w-5 h-5" />
<span>שגיאה בטעינת tools: {error.message}</span>
</CardContent>
</Card>
);
}
if (!data) return null;
return (
<div className="space-y-4">
<div className="flex items-center gap-2 text-sm text-ink-muted">
<Wrench className="w-4 h-4" />
סה&quot;כ {data.count} tools
</div>
{[...grouped.entries()].sort().map(([mod, tools]) => (
<Card key={mod} className="bg-surface border-rule">
<CardContent className="px-6 py-5">
<h2 className="text-navy text-lg mb-3 flex items-center gap-2">
<code dir="ltr">{mod}</code>
<Badge variant="outline" className="text-[0.7rem]">
{tools.length}
</Badge>
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{tools.map((t) => (
<button
key={t.name}
onClick={() => {
setSelected(t);
setOpen(true);
}}
className="text-start rounded-md border border-rule px-3 py-2 hover:bg-rule-soft/40 transition-colors"
>
<code dir="ltr" className="font-mono text-sm text-navy">
{t.name}
</code>
{t.description && (
<p className="text-[0.78rem] text-ink-muted mt-0.5 line-clamp-2">
{t.description}
</p>
)}
</button>
))}
</div>
</CardContent>
</Card>
))}
<ToolDetailDrawer tool={selected} open={open} onOpenChange={setOpen} />
</div>
);
}