diff --git a/apps/web/src/app/admin/gateway/RoutingContent.tsx b/apps/web/src/app/admin/gateway/RoutingContent.tsx index 0251b8e010d..cb5a24db618 100644 --- a/apps/web/src/app/admin/gateway/RoutingContent.tsx +++ b/apps/web/src/app/admin/gateway/RoutingContent.tsx @@ -11,8 +11,10 @@ import { Label } from '@/components/ui/label'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { DEFAULT_VERCEL_ROUTING_ENABLED, + GatewayConfigInputSchema, NOTE_MAX_LENGTH, } from '@kilocode/web-shared/lib/ai-gateway/gateway-config'; +import { formatZodError } from '@/lib/zod/format-zod-error'; export function RoutingContent() { const trpc = useTRPC(); @@ -24,6 +26,7 @@ export function RoutingContent() { const [optOutModelsValue, setOptOutModelsValue] = useState(''); const [noteValue, setNoteValue] = useState(''); const [hasChanges, setHasChanges] = useState(false); + const [validationError, setValidationError] = useState(null); useEffect(() => { if (data) { @@ -43,7 +46,7 @@ export function RoutingContent() { toast.success('Gateway routing configuration updated'); }, onError: error => { - toast.error(error.message || 'Failed to update'); + toast.error(formatZodError(error)); }, }) ); @@ -53,23 +56,20 @@ export function RoutingContent() { return trimmed === '' ? null : trimmed; } - function optOutModels() { - return [ - ...new Set( - optOutModelsValue - .split('\n') - .map(model => model.trim()) - .filter(Boolean) - ), - ]; - } - function handleSave() { - mutation.mutate({ + const parsed = GatewayConfigInputSchema.safeParse({ vercel_routing_enabled: vercelEnabled, - vercel_routing_opt_out_models: optOutModels(), + vercel_routing_opt_out_models: optOutModelsValue + .split('\n') + .filter(model => model.trim() !== ''), note: noteInput(), }); + if (!parsed.success) { + setValidationError(formatZodError(parsed.error)); + return; + } + setValidationError(null); + mutation.mutate(parsed.data); } if (isLoading) { @@ -108,11 +108,17 @@ export function RoutingContent() {