From 01ed0aca935ea29385d09221e7cf5adf847aa0d0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 21:27:15 +0000 Subject: [PATCH] feat(ui): policies/guardrail_selection_modal to shadcn - antd Modal/Button/Checkbox/Divider/Tag + antd icons (CheckCircleOutlined, InfoCircleOutlined) \u2192 shadcn Dialog/Button/ Checkbox/Badge + lucide CheckCircle2/Info/Loader2. - Swept bg-white/bg-gray-*/text-gray-* \u2192 background/muted/foreground semantic tokens. Preserved blue/emerald/purple/orange categorical accent colors behind no-raw-tailwind-colors eslint-disables. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- .../policies/guardrail_selection_modal.tsx | 411 ++++++++++-------- 1 file changed, 232 insertions(+), 179 deletions(-) diff --git a/ui/litellm-dashboard/src/components/policies/guardrail_selection_modal.tsx b/ui/litellm-dashboard/src/components/policies/guardrail_selection_modal.tsx index 82d7aed08bc..026b353e876 100644 --- a/ui/litellm-dashboard/src/components/policies/guardrail_selection_modal.tsx +++ b/ui/litellm-dashboard/src/components/policies/guardrail_selection_modal.tsx @@ -1,18 +1,32 @@ import React, { useState, useEffect } from "react"; -import { Modal, Checkbox, Button, Divider, Tag } from "antd"; -import { CheckCircleOutlined, InfoCircleOutlined } from "@ant-design/icons"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; +import { CheckCircle2, Info, Loader2 } from "lucide-react"; +import { cn } from "@/lib/utils"; interface GuardrailInfo { guardrail_name: string; description: string; alreadyExists: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any definition: any; } interface GuardrailSelectionModalProps { visible: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any template: any; existingGuardrails: Set; + // eslint-disable-next-line @typescript-eslint/no-explicit-any onConfirm: (selectedGuardrails: any[]) => void; onCancel: () => void; isLoading?: boolean; @@ -29,12 +43,12 @@ const GuardrailSelectionModal: React.FC = ({ progressInfo, }) => { const [selectedGuardrails, setSelectedGuardrails] = useState>( - new Set() + new Set(), ); - // Prepare guardrail info with existence status const guardrailsInfo: GuardrailInfo[] = ( template?.guardrailDefinitions || [] + // eslint-disable-next-line @typescript-eslint/no-explicit-any ).map((def: any) => ({ guardrail_name: def.guardrail_name, description: def.guardrail_info?.description || "No description available", @@ -42,7 +56,6 @@ const GuardrailSelectionModal: React.FC = ({ definition: def, })); - // Initialize selection: select only new guardrails by default useEffect(() => { if (visible && template) { const newGuardrails = guardrailsInfo @@ -50,6 +63,7 @@ const GuardrailSelectionModal: React.FC = ({ .map((g) => g.guardrail_name); setSelectedGuardrails(new Set(newGuardrails)); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [visible, template]); const handleToggle = (guardrailName: string) => { @@ -83,200 +97,239 @@ const GuardrailSelectionModal: React.FC = ({ }; const newGuardrailsCount = guardrailsInfo.filter( - (g) => !g.alreadyExists + (g) => !g.alreadyExists, ).length; const existingCount = guardrailsInfo.filter((g) => g.alreadyExists).length; const selectedCount = selectedGuardrails.size; return ( - + (!o ? onCancel() : undefined)}> + +
-

{template?.title}

+ {template?.title} {progressInfo && ( - + // eslint-disable-next-line litellm-ui/no-raw-tailwind-colors + Template {progressInfo.current} of {progressInfo.total} )}
-

+ Review and select guardrails to create for this template -

- - } - open={visible} - onCancel={onCancel} - width={700} - footer={[ - , - , - ]} - > -
- {/* Summary Stats */} -
- -
-
- - {guardrailsInfo.length} total guardrails - - • - - {newGuardrailsCount} new - - {existingCount > 0 && ( - <> - • - - {existingCount} already exist - - - )} -
-
- {newGuardrailsCount > 0 && ( -
- - -
- )} -
+ + - {/* Guardrails List */} -
- {guardrailsInfo.map((guardrail) => ( -
-
-
- {guardrail.alreadyExists ? ( - - ) : ( - handleToggle(guardrail.guardrail_name)} - /> - )} -
-
-
- - {guardrail.guardrail_name} - - {guardrail.alreadyExists && ( - - Already exists - - )} -
-

- {guardrail.description} -

- - {/* Show guardrail type and mode */} -
- - {guardrail.definition?.litellm_params?.guardrail || "unknown"} - - - {guardrail.definition?.litellm_params?.mode || "unknown"} - - {guardrail.definition?.litellm_params?.patterns && ( - - {guardrail.definition.litellm_params.patterns.length} pattern(s) - - )} - {guardrail.definition?.litellm_params?.categories && ( - - {guardrail.definition.litellm_params.categories.length} category/categories - - )} -
-
-
-
- ))} -
- - {guardrailsInfo.length === 0 && ( -
-

No guardrails defined for this template.

-

- This template will use existing guardrails in your system. -

-
- )} - - {/* Discovered Competitors */} - {template?.discoveredCompetitors?.length > 0 && ( - <> - -
-
- ✨ - - AI-Discovered Competitors ({template.discoveredCompetitors.length}) +
+ {/* Summary Stats */} + {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} +
+ {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} + +
+
+ + {guardrailsInfo.length} total guardrails + • + {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} + + {newGuardrailsCount} new + + {existingCount > 0 && ( + <> + • + + {existingCount} already exist + + + )}
-
- {template.discoveredCompetitors.map((name: string) => ( - - {name} - - ))} +
+ {newGuardrailsCount > 0 && ( +
+ +
-

- These competitor names will be automatically blocked by the competitor-name-blocker guardrail. + )} +

+ + {/* Guardrails List */} +
+ {guardrailsInfo.map((guardrail) => ( +
+
+
+ {guardrail.alreadyExists ? ( + // eslint-disable-next-line litellm-ui/no-raw-tailwind-colors + + ) : ( + + handleToggle(guardrail.guardrail_name) + } + /> + )} +
+
+
+ + {guardrail.guardrail_name} + + {guardrail.alreadyExists && ( + + Already exists + + )} +
+

+ {guardrail.description} +

+ + {/* Show guardrail type and mode */} +
+ + {guardrail.definition?.litellm_params?.guardrail || + "unknown"} + + + {guardrail.definition?.litellm_params?.mode || + "unknown"} + + {guardrail.definition?.litellm_params?.patterns && ( + + { + guardrail.definition.litellm_params.patterns + .length + }{" "} + pattern(s) + + )} + {guardrail.definition?.litellm_params?.categories && ( + + { + guardrail.definition.litellm_params.categories + .length + }{" "} + category/categories + + )} +
+
+
+
+ ))} +
+ + {guardrailsInfo.length === 0 && ( +
+

No guardrails defined for this template.

+

+ This template will use existing guardrails in your system.

- - )} - - - - {/* Selected Summary */} -
- {selectedCount > 0 ? ( -

- {selectedCount}{" "} - guardrail{selectedCount > 1 ? "s" : ""} will be created -

- ) : existingCount > 0 ? ( -

- All guardrails already exist. You can proceed to use this template. -

- ) : ( -

- Select at least one guardrail to create, or click "Use Template" to proceed without creating new guardrails. -

)} + + {/* Discovered Competitors */} + {template?.discoveredCompetitors?.length > 0 && ( + <> +
+ {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} +
+
+ ✨ + {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} + + AI-Discovered Competitors ( + {template.discoveredCompetitors.length}) + +
+
+ {template.discoveredCompetitors.map((name: string) => ( + + {name} + + ))} +
+ {/* eslint-disable-next-line litellm-ui/no-raw-tailwind-colors */} +

+ These competitor names will be automatically blocked by the + competitor-name-blocker guardrail. +

+
+ + )} + +
+ + {/* Selected Summary */} +
+ {selectedCount > 0 ? ( +

+ + {selectedCount} + {" "} + guardrail{selectedCount > 1 ? "s" : ""} will be created +

+ ) : existingCount > 0 ? ( + // eslint-disable-next-line litellm-ui/no-raw-tailwind-colors +

+ All guardrails already exist. You can proceed to use this + template. +

+ ) : ( + // eslint-disable-next-line litellm-ui/no-raw-tailwind-colors +

+ Select at least one guardrail to create, or click "Use + Template" to proceed without creating new guardrails. +

+ )} +
-
- + + + + + + +
); };