diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index 1a28d1a650e..e8a86074c99 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -71,6 +71,7 @@ "src/components/view_logs/GuardrailViewer/CompliancePanel.tsx", "src/components/view_logs/LogDetailsDrawer/DrawerHeader.tsx", "src/components/guardrails/pii_components.tsx", + "src/components/policies/policy_info.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/policies/policy_info.tsx b/ui/litellm-dashboard/src/components/policies/policy_info.tsx index bcd5a842fa6..79cc132ebb7 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_info.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_info.tsx @@ -1,22 +1,65 @@ import React, { useState, useEffect, useCallback } from "react"; -import { Card, Badge, Button } from "@tremor/react"; -import { ArrowLeftIcon, PencilIcon } from "@heroicons/react/outline"; -import { Descriptions, Tag, Spin, Divider, Typography, Alert } from "antd"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { cn } from "@/lib/utils"; +import { ArrowLeft, Info, Loader2, Pencil } from "lucide-react"; import { Policy } from "./types"; import { PipelineInfoDisplay } from "./pipeline_flow_builder"; import { getResolvedGuardrails } from "../networking"; -const { Title, Text } = Typography; - interface PolicyInfoViewProps { policyId: string; onClose: () => void; onEdit: (policy: Policy) => void; accessToken: string | null; isAdmin: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any getPolicy: (accessToken: string, policyId: string) => Promise; } +const Section: React.FC<{ + title: string; + children: React.ReactNode; +}> = ({ title, children }) => ( +
+
+ {title} +
+
+ {children} +
+); + +const InfoAlert: React.FC<{ + title: React.ReactNode; + description?: React.ReactNode; +}> = ({ title, description }) => ( +
+ +
+
{title}
+ {description &&
{description}
} +
+
+); + +const DescRow: React.FC<{ + label: string; + children: React.ReactNode; + first?: boolean; +}> = ({ label, children, first }) => ( +
+
{label}
+
{children}
+
+); + const PolicyInfoView: React.FC = ({ policyId, onClose, @@ -28,7 +71,6 @@ const PolicyInfoView: React.FC = ({ const [policy, setPolicy] = useState(null); const [isLoading, setIsLoading] = useState(true); const [resolvedGuardrails, setResolvedGuardrails] = useState([]); - const [isLoadingResolved, setIsLoadingResolved] = useState(false); const fetchPolicy = useCallback(async () => { if (!accessToken || !policyId) return; @@ -37,16 +79,12 @@ const PolicyInfoView: React.FC = ({ try { const data = await getPolicy(accessToken, policyId); setPolicy(data); - - // Also fetch resolved guardrails - setIsLoadingResolved(true); + try { const resolvedData = await getResolvedGuardrails(accessToken, policyId); setResolvedGuardrails(resolvedData.resolved_guardrails || []); } catch (error) { console.error("Error fetching resolved guardrails:", error); - } finally { - setIsLoadingResolved(false); } } catch (error) { console.error("Error fetching policy:", error); @@ -62,17 +100,16 @@ const PolicyInfoView: React.FC = ({ if (isLoading) { return (
- +
); } if (!policy) { return ( - - Policy not found -
-
@@ -80,142 +117,145 @@ const PolicyInfoView: React.FC = ({ } return ( - +
- {isAdmin && ( - )}
- {policy.policy_name} +

{policy.policy_name}

- - - {policy.policy_id} - - - {policy.description || No description} - - - {policy.inherit ? ( - {policy.inherit} - ) : ( - None +
+ + + {policy.policy_id} + + + + {policy.description || ( + No description )} - - + + + {policy.inherit ? ( + + {policy.inherit} + + ) : ( + None + )} + + {policy.created_at ? new Date(policy.created_at).toLocaleString() : "-"} - - + + {policy.updated_at ? new Date(policy.updated_at).toLocaleString() : "-"} - - + +
{policy.pipeline && ( <> - - Pipeline Flow - - - +
+ + +
)} - - Guardrails Configuration - - - {resolvedGuardrails.length > 0 && ( - - - Final guardrails that will be applied (including inheritance): - -
- {resolvedGuardrails.map((g) => ( - - {g} - - ))} +
+ {resolvedGuardrails.length > 0 && ( + +
+ Final guardrails that will be applied (including + inheritance): +
+
+ {resolvedGuardrails.map((g) => ( + + {g} + + ))} +
+ } + /> + )} + +
+ +
+ {policy.guardrails_add && policy.guardrails_add.length > 0 ? ( + policy.guardrails_add.map((g) => ( + + {g} + + )) + ) : ( + None + )}
- } - type="info" - showIcon - style={{ marginBottom: 16 }} - /> - )} +
+ +
+ {policy.guardrails_remove && + policy.guardrails_remove.length > 0 ? ( + policy.guardrails_remove.map((g) => ( + + {g} + + )) + ) : ( + None + )} +
+
+
+ - - -
- {policy.guardrails_add && policy.guardrails_add.length > 0 ? ( - policy.guardrails_add.map((g) => ( - - {g} - - )) +
+
+ + {policy.condition?.model ? ( + + {typeof policy.condition.model === "string" + ? policy.condition.model + : JSON.stringify(policy.condition.model)} + ) : ( - None + + No model condition (applies to all models) + )} -
- - -
- {policy.guardrails_remove && policy.guardrails_remove.length > 0 ? ( - policy.guardrails_remove.map((g) => ( - - {g} - - )) - ) : ( - None - )} -
-
- - - - Conditions - - - - - {policy.condition?.model ? ( - - {typeof policy.condition.model === "string" - ? policy.condition.model - : JSON.stringify(policy.condition.model)} - - ) : ( - No model condition (applies to all models) - )} - - + +
+
);