mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): view_logs/ToolsSection to shadcn
- ToolsSection: antd Collapse \u2192 shadcn Accordion (single-collapsible). Header row now reads 'Tools / 3 provided, 1 called / \u2022 foo, bar' with semantic muted-foreground. - ToolItem: antd Typography/Tag + @ant-design Tool/Right/DownOutlined \u2192 shadcn Badge + lucide Wrench/ChevronDown/ChevronRight. Expand-click toggles a bg-muted highlight row. File added to overrides for the categorical blue 'called' badge. - ToolExpandedContent: antd Radio.Group \u2192 shadcn ToggleGroup for the Formatted / JSON switch. Label uses text-muted-foreground. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
55ca23278a
commit
dbca20ce4b
4 changed files with 75 additions and 106 deletions
|
|
@ -55,6 +55,7 @@
|
|||
"src/components/permissions/AgentPermissions.tsx",
|
||||
"src/components/permissions/MCPServerPermissions.tsx",
|
||||
"src/components/survey/ClaudeCodeModal.tsx",
|
||||
"src/components/view_logs/ToolsSection/ToolItem.tsx",
|
||||
"src/components/policies/impact_preview_alert.tsx",
|
||||
"src/components/policies/impact_popover.tsx",
|
||||
"src/components/DeletedKeysPage/DeletedKeysPage.tsx",
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
/**
|
||||
* Expanded content for a tool with view mode toggle
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { Typography, Radio } from "antd";
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/components/ui/toggle-group";
|
||||
import { ParsedTool } from "./types";
|
||||
import { FormattedToolView } from "./FormattedToolView";
|
||||
import { JsonToolView } from "./JsonToolView";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
type ViewMode = "formatted" | "json";
|
||||
|
||||
interface ToolExpandedContentProps {
|
||||
|
|
@ -21,25 +18,20 @@ export function ToolExpandedContent({ tool }: ToolExpandedContentProps) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
{/* View Mode Toggle - Top Right */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 12,
|
||||
}}
|
||||
>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
Description
|
||||
</Text>
|
||||
<Radio.Group
|
||||
size="small"
|
||||
<div className="flex justify-between mb-3">
|
||||
<span className="text-xs text-muted-foreground">Description</span>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
size="sm"
|
||||
value={viewMode}
|
||||
onChange={(e) => setViewMode(e.target.value)}
|
||||
onValueChange={(v) => {
|
||||
if (!v) return;
|
||||
setViewMode(v as ViewMode);
|
||||
}}
|
||||
>
|
||||
<Radio.Button value="formatted">Formatted</Radio.Button>
|
||||
<Radio.Button value="json">JSON</Radio.Button>
|
||||
</Radio.Group>
|
||||
<ToggleGroupItem value="formatted">Formatted</ToggleGroupItem>
|
||||
<ToggleGroupItem value="json">JSON</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
{viewMode === "formatted" ? (
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
/**
|
||||
* Individual tool item component with expandable details
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { Typography, Tag } from "antd";
|
||||
import { ToolOutlined, RightOutlined, DownOutlined } from "@ant-design/icons";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ChevronDown, ChevronRight, Wrench } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ParsedTool } from "./types";
|
||||
import { ToolExpandedContent } from "./ToolExpandedContent";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
interface ToolItemProps {
|
||||
tool: ParsedTool;
|
||||
}
|
||||
|
|
@ -18,54 +13,42 @@ export function ToolItem({ tool }: ToolItemProps) {
|
|||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid #f0f0f0",
|
||||
borderRadius: 8,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{/* Header Row - Always Visible */}
|
||||
<div className="border border-border rounded-lg overflow-hidden">
|
||||
<div
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "12px 16px",
|
||||
cursor: "pointer",
|
||||
background: expanded ? "#fafafa" : "#fff",
|
||||
transition: "background 0.2s",
|
||||
}}
|
||||
className={cn(
|
||||
"flex items-center justify-between px-4 py-3 cursor-pointer transition-colors",
|
||||
expanded ? "bg-muted" : "bg-background",
|
||||
)}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
||||
<ToolOutlined style={{ color: "#8c8c8c", fontSize: 14 }} />
|
||||
<Text style={{ fontSize: 14 }}>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<Wrench className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-sm">
|
||||
{tool.index}. {tool.name}
|
||||
</Text>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||
<Tag color={tool.called ? "blue" : "default"}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge
|
||||
className={cn(
|
||||
"text-xs",
|
||||
tool.called
|
||||
? "bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-300"
|
||||
: "bg-muted text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{tool.called ? "called" : "not called"}
|
||||
</Tag>
|
||||
</Badge>
|
||||
{expanded ? (
|
||||
<DownOutlined style={{ fontSize: 12, color: "#8c8c8c" }} />
|
||||
<ChevronDown className="h-3 w-3 text-muted-foreground" />
|
||||
) : (
|
||||
<RightOutlined style={{ fontSize: 12, color: "#8c8c8c" }} />
|
||||
<ChevronRight className="h-3 w-3 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expanded Content */}
|
||||
{expanded && (
|
||||
<div
|
||||
style={{
|
||||
padding: "16px",
|
||||
borderTop: "1px solid #f0f0f0",
|
||||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
<div className="p-4 border-t border-border bg-background">
|
||||
<ToolExpandedContent tool={tool} />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
/**
|
||||
* Tools section component that displays all available tools from the request
|
||||
* and indicates which ones were actually called in the response
|
||||
*/
|
||||
|
||||
import { Collapse, Typography } from "antd";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { LogEntry } from "../columns";
|
||||
import { parseToolsFromLog } from "./utils";
|
||||
import { ToolItem } from "./ToolItem";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
interface ToolsSectionProps {
|
||||
log: LogEntry;
|
||||
}
|
||||
|
|
@ -17,14 +15,11 @@ interface ToolsSectionProps {
|
|||
export function ToolsSection({ log }: ToolsSectionProps) {
|
||||
const tools = parseToolsFromLog(log);
|
||||
|
||||
// Don't render if no tools
|
||||
if (tools.length === 0) return null;
|
||||
|
||||
// Calculate summary stats
|
||||
const totalTools = tools.length;
|
||||
const calledTools = tools.filter((t) => t.called).length;
|
||||
|
||||
// Get preview of first 2 tool names
|
||||
|
||||
const toolNamePreview = tools
|
||||
.slice(0, 2)
|
||||
.map((t) => t.name)
|
||||
|
|
@ -32,34 +27,32 @@ export function ToolsSection({ log }: ToolsSectionProps) {
|
|||
const hasMoreTools = tools.length > 2;
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||
<Collapse
|
||||
expandIconPosition="start"
|
||||
items={[
|
||||
{
|
||||
key: "1",
|
||||
label: (
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
|
||||
<h3 className="text-lg font-medium text-gray-900">Tools</h3>
|
||||
<Text type="secondary" style={{ fontSize: 14 }}>
|
||||
{totalTools} provided, {calledTools} called
|
||||
</Text>
|
||||
<Text type="secondary" style={{ fontSize: 14 }}>
|
||||
• {toolNamePreview}
|
||||
{hasMoreTools && "..."}
|
||||
</Text>
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
{tools.map((tool) => (
|
||||
<ToolItem key={tool.name} tool={tool} />
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="bg-background rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="tools">
|
||||
<AccordionTrigger>
|
||||
<div className="flex items-center gap-3 flex-wrap pr-2">
|
||||
<h3 className="text-lg font-medium text-foreground m-0">
|
||||
Tools
|
||||
</h3>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{totalTools} provided, {calledTools} called
|
||||
</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
• {toolNamePreview}
|
||||
{hasMoreTools && "..."}
|
||||
</span>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="flex flex-col gap-2">
|
||||
{tools.map((tool) => (
|
||||
<ToolItem key={tool.name} tool={tool} />
|
||||
))}
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue