diff --git a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx index 72b3fa15be5..0aad42feb08 100644 --- a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx @@ -109,6 +109,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a const [selectedPatterns, setSelectedPatterns] = useState([]); const [blockedWords, setBlockedWords] = useState([]); const [selectedContentCategories, setSelectedContentCategories] = useState([]); + const [pendingCategorySelection, setPendingCategorySelection] = useState(""); const [toolPermissionConfig, setToolPermissionConfig] = useState({ rules: [], default_action: "deny", @@ -169,6 +170,12 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a setGlobalSeverityThreshold(2); setCategorySpecificThresholds({}); + // Reset Content Filter selections + setSelectedPatterns([]); + setBlockedWords([]); + setSelectedContentCategories([]); + setPendingCategorySelection(""); + setToolPermissionConfig({ rules: [], default_action: "deny", @@ -247,6 +254,39 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a setCurrentStep(currentStep - 1); }; + const handleAddAndContinue = () => { + if (!pendingCategorySelection || !guardrailSettings) return; + + const contentFilterSettings = guardrailSettings.content_filter_settings; + if (!contentFilterSettings) return; + + const category = contentFilterSettings.content_categories?.find((c) => c.name === pendingCategorySelection); + if (!category) return; + + // Check if already added + if (selectedContentCategories.some((c) => c.category === pendingCategorySelection)) { + setPendingCategorySelection(""); + setCurrentStep(currentStep + 1); + return; + } + + // Add the category + setSelectedContentCategories([ + ...selectedContentCategories, + { + id: `category-${Date.now()}`, + category: category.name, + display_name: category.display_name, + action: category.default_action as "BLOCK" | "MASK", + severity_threshold: "medium", + }, + ]); + + // Clear pending selection and advance to next step + setPendingCategorySelection(""); + setCurrentStep(currentStep + 1); + }; + const resetForm = () => { form.resetFields(); setSelectedProvider(null); @@ -258,6 +298,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a setSelectedPatterns([]); setBlockedWords([]); setSelectedContentCategories([]); + setPendingCategorySelection(""); setToolPermissionConfig({ rules: [], default_action: "deny", @@ -667,6 +708,8 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a selectedContentCategories.map((c) => (c.id === id ? { ...c, [field]: value } : c)) ); }} + pendingCategorySelection={pendingCategorySelection} + onPendingCategorySelectionChange={setPendingCategorySelection} accessToken={accessToken} showStep={step} /> @@ -729,6 +772,8 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a const renderStepButtons = () => { const totalSteps = shouldRenderContentFilterConfigSettings(selectedProvider) ? 4 : 2; const isLastStep = currentStep === totalSteps - 1; + const isCategoriesStep = shouldRenderContentFilterConfigSettings(selectedProvider) && currentStep === 1; + const hasPendingCategory = pendingCategorySelection !== ""; return (
@@ -737,11 +782,30 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a Previous )} - {!isLastStep && } - {isLastStep && ( - + {isCategoriesStep ? ( + <> + + + + ) : ( + <> + {!isLastStep && ( + + )} + {isLastStep && ( + + )} + )}