forked from cardosofelipe/fast-next-template
fix(frontend): show validation errors when agent type form fails
When form validation fails (e.g., personality_prompt is empty), the form would silently not submit. Now it shows a toast with the first error and navigates to the tab containing the error field. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,10 @@
|
|||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useCallback } from 'react';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller, type FieldErrors } from 'react-hook-form';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
@@ -89,6 +90,30 @@ export function AgentTypeForm({
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = form;
|
} = form;
|
||||||
|
|
||||||
|
// Handle form validation errors - show toast with first error
|
||||||
|
const handleFormError = useCallback((formErrors: FieldErrors<AgentTypeCreateFormValues>) => {
|
||||||
|
// Find the first error and show it
|
||||||
|
const firstErrorKey = Object.keys(formErrors)[0] as keyof AgentTypeCreateFormValues;
|
||||||
|
if (firstErrorKey) {
|
||||||
|
const error = formErrors[firstErrorKey];
|
||||||
|
const message = error && 'message' in error ? error.message : 'Validation error';
|
||||||
|
toast.error('Please fix form errors', {
|
||||||
|
description: `${String(firstErrorKey)}: ${message}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Navigate to the tab containing the error
|
||||||
|
if (['name', 'slug', 'description', 'expertise', 'is_active'].includes(firstErrorKey)) {
|
||||||
|
setActiveTab('basic');
|
||||||
|
} else if (['primary_model', 'fallback_models', 'model_params'].includes(firstErrorKey)) {
|
||||||
|
setActiveTab('model');
|
||||||
|
} else if (['mcp_servers', 'tool_permissions'].includes(firstErrorKey)) {
|
||||||
|
setActiveTab('permissions');
|
||||||
|
} else if (firstErrorKey === 'personality_prompt') {
|
||||||
|
setActiveTab('personality');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const watchName = watch('name');
|
const watchName = watch('name');
|
||||||
/* istanbul ignore next -- defensive fallback, expertise always has default */
|
/* istanbul ignore next -- defensive fallback, expertise always has default */
|
||||||
const watchExpertise = watch('expertise') || [];
|
const watchExpertise = watch('expertise') || [];
|
||||||
@@ -133,7 +158,7 @@ export function AgentTypeForm({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className={className}>
|
<form onSubmit={handleSubmit(onSubmit, handleFormError)} className={className}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-6 flex items-center gap-4">
|
<div className="mb-6 flex items-center gap-4">
|
||||||
<Button type="button" variant="ghost" size="icon" onClick={onCancel}>
|
<Button type="button" variant="ghost" size="icon" onClick={onCancel}>
|
||||||
|
|||||||
Reference in New Issue
Block a user