feat(ui): guardrails/GuardrailTestPanel to shadcn

- @tremor Button + antd Input.TextArea/Typography/Tooltip + @ant-design
  Copy/InfoCircle \u2192 shadcn Button/Textarea/Tooltip + lucide Copy/Info.
- Blue guardrail-name chips preserved as categorical accent (file
  added to .eslintrc.json overrides).

Gates: TS \u2713 | Build \u2713.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-23 14:22:17 +00:00
parent 81ebf913e8
commit 11049a1141
No known key found for this signature in database
2 changed files with 58 additions and 32 deletions

View file

@ -63,6 +63,7 @@
"src/components/prompts/variable_textarea.tsx",
"src/components/chat/MCPCredentialsTab.tsx",
"src/components/common_components/KeyLifecycleSettings.tsx",
"src/components/guardrails/GuardrailTestPanel.tsx",
"src/components/prompts/prompt_editor_view/PromptEditorHeader.tsx",
"src/components/prompts/prompt_editor_view/VersionHistorySidePanel.tsx",
"src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.tsx",

View file

@ -1,19 +1,26 @@
import React, { useState } from "react";
import { Button } from "@tremor/react";
import { Input, Typography, Tooltip } from "antd";
import { CopyOutlined, InfoCircleOutlined } from "@ant-design/icons";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Copy, Info } from "lucide-react";
import NotificationsManager from "../molecules/notifications_manager";
import GuardrailTestResults from "./GuardrailTestResults";
const { TextArea } = Input;
const { Text } = Typography;
interface GuardrailTestPanelProps {
guardrailNames: string[];
onSubmit: (text: string) => void;
isLoading: boolean;
results: Array<{ guardrailName: string; response_text: string; latency: number }> | null;
errors: Array<{ guardrailName: string; error: Error; latency: number }> | null;
results:
| Array<{ guardrailName: string; response_text: string; latency: number }>
| null;
errors:
| Array<{ guardrailName: string; error: Error; latency: number }>
| null;
onClose: () => void;
}
@ -23,7 +30,6 @@ export function GuardrailTestPanel({
isLoading,
results,
errors,
onClose,
}: GuardrailTestPanelProps) {
const [inputText, setInputText] = useState("");
@ -82,53 +88,65 @@ export function GuardrailTestPanel({
return (
<div className="space-y-4 h-full flex flex-col">
{/* Header */}
<div className="flex items-center justify-between pb-3 border-b border-gray-200">
<div className="flex items-center justify-between pb-3 border-b border-border">
<div className="flex items-center space-x-3">
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 mb-1">
<h2 className="text-lg font-semibold text-gray-900">Test Guardrails:</h2>
<h2 className="text-lg font-semibold text-foreground">
Test Guardrails:
</h2>
<div className="flex flex-wrap gap-2">
{guardrailNames.map((name) => (
<div
key={name}
className="inline-flex items-center space-x-1 bg-blue-50 px-3 py-1 rounded-md border border-blue-200"
className="inline-flex items-center space-x-1 bg-blue-50 dark:bg-blue-950/30 px-3 py-1 rounded-md border border-blue-200 dark:border-blue-900"
>
<span className="font-mono text-blue-700 font-medium text-sm">{name}</span>
<span className="font-mono text-blue-700 dark:text-blue-300 font-medium text-sm">
{name}
</span>
</div>
))}
</div>
</div>
<p className="text-sm text-gray-500">
Test {guardrailNames.length > 1 ? "guardrails" : "guardrail"} and compare results
<p className="text-sm text-muted-foreground">
Test {guardrailNames.length > 1 ? "guardrails" : "guardrail"}{" "}
and compare results
</p>
</div>
</div>
</div>
{/* Input Section */}
<div className="flex-1 overflow-auto space-y-4">
<div className="space-y-3">
<div>
<div className="flex justify-between items-center mb-2">
<div className="flex items-center gap-2">
<label className="text-sm font-medium text-gray-700">Input Text</label>
<Tooltip title="Press Enter to submit. Use Shift+Enter for new line.">
<InfoCircleOutlined className="text-gray-400 cursor-help" />
</Tooltip>
<label className="text-sm font-medium text-foreground">
Input Text
</label>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Info className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
Press Enter to submit. Use Shift+Enter for new line.
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
{inputText && (
<Button
size="xs"
size="sm"
variant="secondary"
icon={CopyOutlined}
onClick={handleCopyInput}
>
<Copy className="h-3.5 w-3.5" />
Copy Input
</Button>
)}
</div>
<TextArea
<Textarea
value={inputText}
onChange={(e) => setInputText(e.target.value)}
onKeyDown={handleKeyDown}
@ -137,18 +155,27 @@ export function GuardrailTestPanel({
className="font-mono text-sm"
/>
<div className="flex justify-between items-center mt-1">
<Text className="text-xs text-gray-500">
Press <kbd className="px-1 py-0.5 bg-gray-100 border border-gray-300 rounded text-xs">Enter</kbd> to submit • <kbd className="px-1 py-0.5 bg-gray-100 border border-gray-300 rounded text-xs">Shift+Enter</kbd> for new line
</Text>
<Text className="text-xs text-gray-500">Characters: {inputText.length}</Text>
<span className="text-xs text-muted-foreground">
Press{" "}
<kbd className="px-1 py-0.5 bg-muted border border-border rounded text-xs">
Enter
</kbd>{" "}
to submit •{" "}
<kbd className="px-1 py-0.5 bg-muted border border-border rounded text-xs">
Shift+Enter
</kbd>{" "}
for new line
</span>
<span className="text-xs text-muted-foreground">
Characters: {inputText.length}
</span>
</div>
</div>
<div className="pt-2">
<Button
onClick={handleSubmit}
loading={isLoading}
disabled={!inputText.trim()}
disabled={isLoading || !inputText.trim()}
className="w-full"
>
{isLoading
@ -158,7 +185,6 @@ export function GuardrailTestPanel({
</div>
</div>
{/* Results Section */}
<GuardrailTestResults results={results} errors={errors} />
</div>
</div>
@ -166,4 +192,3 @@ export function GuardrailTestPanel({
}
export default GuardrailTestPanel;