diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 2a0430244ba..34010baf1e0 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -65,6 +65,7 @@ "src/components/common_components/KeyLifecycleSettings.tsx", "src/components/guardrails/GuardrailTestPanel.tsx", "src/components/guardrails/GuardrailTestResults.tsx", + "src/components/guardrails/GuardrailTestPlayground.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", diff --git a/ui/litellm-dashboard/src/components/guardrails/GuardrailTestPlayground.tsx b/ui/litellm-dashboard/src/components/guardrails/GuardrailTestPlayground.tsx index 7ede8f4c8d7..7fe999e48b3 100644 --- a/ui/litellm-dashboard/src/components/guardrails/GuardrailTestPlayground.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/GuardrailTestPlayground.tsx @@ -1,6 +1,8 @@ import React, { useState } from "react"; -import { Card, List, Empty, Spin, Input, Typography } from "antd"; -import { ExperimentOutlined, SearchOutlined } from "@ant-design/icons"; +import { Card } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { FlaskConical, Loader2, Search } from "lucide-react"; +import { cn } from "@/lib/utils"; import GuardrailTestPanel from "./GuardrailTestPanel"; import { applyGuardrail } from "../networking"; import NotificationsManager from "../molecules/notifications_manager"; @@ -13,6 +15,7 @@ interface GuardrailItem { mode: string; default_on: boolean; }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any guardrail_info: Record | null; created_at?: string; updated_at?: string; @@ -41,16 +44,19 @@ const GuardrailTestPlayground: React.FC = ({ guardrailsList, isLoading, accessToken, - onClose, }) => { - const [selectedGuardrails, setSelectedGuardrails] = useState>(new Set()); + const [selectedGuardrails, setSelectedGuardrails] = useState>( + new Set(), + ); const [searchQuery, setSearchQuery] = useState(""); const [testResults, setTestResults] = useState([]); const [testErrors, setTestErrors] = useState([]); const [isTesting, setIsTesting] = useState(false); const filteredGuardrails = guardrailsList.filter((guardrail) => - guardrail.guardrail_name?.toLowerCase().includes(searchQuery.toLowerCase()) + guardrail.guardrail_name + ?.toLowerCase() + .includes(searchQuery.toLowerCase()), ); const toggleGuardrailSelection = (guardrailName: string) => { @@ -79,7 +85,13 @@ const GuardrailTestPlayground: React.FC = ({ Array.from(selectedGuardrails).map(async (guardrailName) => { const startTime = Date.now(); try { - const result = await applyGuardrail(accessToken, guardrailName, text, null, null); + const result = await applyGuardrail( + accessToken, + guardrailName, + text, + null, + null, + ); const latency = Date.now() - startTime; results.push({ guardrailName, @@ -95,7 +107,7 @@ const GuardrailTestPlayground: React.FC = ({ latency, }); } - }) + }), ); setTestResults(results); @@ -104,122 +116,121 @@ const GuardrailTestPlayground: React.FC = ({ if (results.length > 0) { NotificationsManager.success( - `${results.length} guardrail${results.length > 1 ? "s" : ""} applied successfully` + `${results.length} guardrail${results.length > 1 ? "s" : ""} applied successfully`, ); } if (errors.length > 0) { NotificationsManager.fromBackend( - `${errors.length} guardrail${errors.length > 1 ? "s" : ""} failed` + `${errors.length} guardrail${errors.length > 1 ? "s" : ""} failed`, ); } }; return (
- +
- {/* Left Sidebar - Guardrails List */} -
-
+
+

Guardrails

- } - placeholder="Search guardrails..." - value={searchQuery} - onChange={(e) => setSearchQuery(e.target.value)} - /> +
+ + setSearchQuery(e.target.value)} + className="pl-8" + /> +
{isLoading ? (
- +
) : filteredGuardrails.length === 0 ? ( -
- +
+ {searchQuery + ? "No guardrails match your search" + : "No guardrails available"}
) : ( - ( - { - if (guardrail.guardrail_name) { - toggleGuardrailSelection(guardrail.guardrail_name); - } - }} - style={{ paddingLeft: 24, paddingRight: 16 }} - className={`cursor-pointer hover:bg-gray-50 transition-colors ${ - selectedGuardrails.has(guardrail.guardrail_name || "") - ? "bg-blue-50 border-l-4 border-l-blue-500" - : "border-l-4 border-l-transparent" - }`} - > - - - - {guardrail.guardrail_name} +
    + {filteredGuardrails.map((guardrail) => { + const isSelected = selectedGuardrails.has( + guardrail.guardrail_name || "", + ); + return ( +
  • { + if (guardrail.guardrail_name) { + toggleGuardrailSelection(guardrail.guardrail_name); + } + }} + className={cn( + "pl-6 pr-4 py-3 cursor-pointer hover:bg-muted transition-colors border-l-4", + isSelected + ? "bg-blue-50 dark:bg-blue-950/30 border-l-blue-500" + : "border-l-transparent", + )} + > +
    + + + {guardrail.guardrail_name} + +
    +
    +
    + Type: + + {guardrail.litellm_params.guardrail}
    - } - description={ -
    -
    - Type: - - {guardrail.litellm_params.guardrail} - -
    -
    - Mode: - - {guardrail.litellm_params.mode} - -
    +
    + Mode: + + {guardrail.litellm_params.mode} +
    - } - /> - - )} - /> +
    +
  • + ); + })} +
)}
-
- - {selectedGuardrails.size} of {filteredGuardrails.length} selected - +
+ + {selectedGuardrails.size} of {filteredGuardrails.length}{" "} + selected +
- {/* Right Panel - Test Area */} -
-
- +
+
+

Guardrail Testing Playground - +

{selectedGuardrails.size === 0 ? ( -
- - +
+ +

Select Guardrails to Test - - - Choose one or more guardrails from the left sidebar to start testing and - comparing results. - +

+

+ Choose one or more guardrails from the left sidebar to + start testing and comparing results. +

) : (
@@ -242,4 +253,3 @@ const GuardrailTestPlayground: React.FC = ({ }; export default GuardrailTestPlayground; -